編輯:Android開發實例
前言
之前一直在講AndroidUI的內容,但是還沒有完結,之後會慢慢補充。今天講講其他的,關於數據持久化的內容。對於一個應用程序而言,不可避免的要能夠對數據進行存儲,Android程序也不例外。而在Android中,提供了幾種實現數據持久化的方法。後面會分別介紹。
在Android中,可以使用幾種方式實現數據持久化:
後面幾天會分別介紹以上幾種方式實現的數據持久化,對於SharedPreferences而言,之前寫過一篇博客,但是自己不是很滿意,之後有時間會再重新寫一份關於SharedPreferences的博客,有興趣的朋友可以先去看看,http://www.fengfly.com/plus/view-213364-1.html。今天先介紹Internal Storage以及External Storage。
Internal Storage
內部存儲,在Android中,開發者可以直接使用設備的內部存儲器中保存文件,默認情況下,以這種方式保存的和數據是只能被當前程序訪問,在其他程序中是無法訪問到的,而當用戶卸載該程序的時候,這些文件也會隨之被刪除。
使用內部存儲保存數據的方式,基本上也是先獲得一個文件的輸出流,然後以write()的方式把待寫入的信息寫入到這個輸出流中,最後關閉流即可,這些都是Java中IO流的操作。具體步驟如下:
上面介紹的Context.openFileOutput()方法有兩個重載函數,它們的簽名分別是:
上面第二個重載函數中,mode為一個int類型的數據,這個一般使用Context對象中設置好的常量參數,有如下幾個:
還有幾個方法需要特別注意一下,這幾個方法對於文件關系提供了更好的支持,配合上面介紹的方式,就可以對文件的數據進行常規的CRUD操作(增刪改查),方法如下:
講了這麼多,下面通過一個簡單的Demo來演示一下上面提到的內容。在這個Demo中,指定文件名和內容,既可創建文件,並且可以對其內容進行追加、修改、刪除、查詢等操作。
布局代碼:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="file name:" />
- <EditText
- android:id="@+id/etInternalFilename"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Content:" />
- <EditText
- android:id="@+id/etInternalContent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <Button
- android:id="@+id/btnInternalSave"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="save" />
- <Button
- android:id="@+id/btnInternalDelete"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="delete" />
- <Button
- android:id="@+id/btnInternalAppend"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="append" />
- <Button
- android:id="@+id/btnInternalQuery"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="query" />
- </LinearLayout>
- <!-- 以一個ListView的形式展示當前程序內部存儲路徑下的所有文件 -->
- <ListView
- android:id="@+id/lvInternalData"
- android:layout_width="match_parent"
- android:layout_height="fill_parent" >
- </ListView>
- </LinearLayout>
專門寫一個內部存儲的操作類,對其實現CRUD操作:
- package com.example.internal;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import android.content.Context;
- import android.os.Environment;
- import android.util.Log;
- public class MyInternalStorage {
- //需要保存當前調用對象的Context
- private Context context;
- public MyInternalStorage(Context context) {
- this.context = context;
- }
- /**
- * 保存內容到內部存儲器中
- * @param filename 文件名
- * @param content 內容
- */
- public void save(String filename, String content) throws IOException {
- // FileOutputStream fos=context.openFileOutput(filename,
- // Context.MODE_PRIVATE);
- File file = new File(context.getFilesDir(), filename);
- FileOutputStream fos = new FileOutputStream(file);
- fos.write(content.getBytes());
- fos.close();
- }
- /**
- * 通過文件名獲取內容
- * @param filename 文件名
- * @return 文件內容
- */
- public String get(String filename) throws IOException {
- FileInputStream fis = context.openFileInput(filename);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] data = new byte[1024];
- int len = -1;
- while ((len = fis.read(data)) != -1) {
- baos.write(data, 0, len);
- }
- return new String(baos.toByteArray());
- }
- /**
- * 以追加的方式在文件的末尾添加內容
- * @param filename 文件名
- * @param content 追加的內容
- */
- public void append(String filename, String content) throws IOException {
- FileOutputStream fos = context.openFileOutput(filename,
- Context.MODE_APPEND);
- fos.write(content.getBytes());
- fos.close();
- }
- /**
- * 刪除文件
- * @param filename 文件名
- * @return 是否成功
- */
- public boolean delete(String filename) {
- return context.deleteFile(filename);
- }
- /**
- * 獲取內部存儲路徑下的所有文件名
- * @return 文件名數組
- */
- public String[] queryAllFile() {
- return context.fileList();
- }
- }
Activity代碼:
- package com.example.datastoragedemo;
- import java.io.IOException;
- import com.example.internal.MyInternalStorage;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.ArrayAdapter;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ListView;
- import android.widget.Toast;
- public class InternalStorageActivity extends Activity {
- private EditText etFilename, etContent;
- private Button btnSave, btnQuery, btnDelete, btnAppend;
- private ListView lvData;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_internalstorage);
- etFilename = (EditText) findViewById(R.id.etInternalFilename);
- etContent = (EditText) findViewById(R.id.etInternalContent);
- btnSave = (Button) findViewById(R.id.btnInternalSave);
- btnQuery = (Button) findViewById(R.id.btnInternalQuery);
- btnDelete = (Button) findViewById(R.id.btnInternalDelete);
- btnAppend = (Button) findViewById(R.id.btnInternalAppend);
- lvData = (ListView) findViewById(R.id.lvInternalData);
- btnSave.setOnClickListener(click);
- btnQuery.setOnClickListener(click);
- btnDelete.setOnClickListener(click);
- btnAppend.setOnClickListener(click);
- }
- private View.OnClickListener click = new OnClickListener() {
- @Override
- public void onClick(View v) {
- MyInternalStorage myInternal = null;
- String filename = null;
- String content = null;
- switch (v.getId()) {
- case R.id.btnInternalSave:
- filename = etFilename.getText().toString();
- content = etContent.getText().toString();
- myInternal = new MyInternalStorage(InternalStorageActivity.this);
- try {
- myInternal.save(filename, content);
- Toast.makeText(InternalStorageActivity.this, "保存文件成功",
- Toast.LENGTH_SHORT).show();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- Toast.makeText(InternalStorageActivity.this, "保存文件失敗",
- Toast.LENGTH_SHORT).show();
- }
- break;
- case R.id.btnInternalDelete:
- filename = etFilename.getText().toString();
- myInternal = new MyInternalStorage(InternalStorageActivity.this);
- myInternal.delete(filename);
- Toast.makeText(InternalStorageActivity.this, "刪除文件成功",
- Toast.LENGTH_SHORT).show();
- break;
- case R.id.btnInternalQuery:
- myInternal = new MyInternalStorage(InternalStorageActivity.this);
- String[] files = myInternal.queryAllFile();
- ArrayAdapter<String> fileArray = new ArrayAdapter<String>(
- InternalStorageActivity.this,
- android.R.layout.simple_list_item_1, files);
- lvData.setAdapter(fileArray);
- Toast.makeText(InternalStorageActivity.this, "查詢文件列表",
- Toast.LENGTH_SHORT).show();
- break;
- case R.id.btnInternalAppend:
- filename = etFilename.getText().toString();
- content = etContent.getText().toString();
- myInternal = new MyInternalStorage(InternalStorageActivity.this);
- try {
- myInternal.append(filename, content);
- Toast.makeText(InternalStorageActivity.this, "文件內容追加成功",
- Toast.LENGTH_SHORT).show();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- Toast.makeText(InternalStorageActivity.this, "文件內容追加失敗",
- Toast.LENGTH_SHORT).show();
- }
- break;
- }
- }
- };
- private OnItemClickListener itemClick = new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position,
- long id) {
- ListView lv = (ListView) parent;
- ArrayAdapter<String> adapter = (ArrayAdapter<String>) lv
- .getAdapter();
- String filename = adapter.getItem(position);
- etFilename.setText(filename);
- MyInternalStorage myInternal = new MyInternalStorage(
- InternalStorageActivity.this);
- String content;
- try {
- content = myInternal.get(filename);
- etContent.setText(content);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- };
- }
效果展示,在示例中,先添加三個文件,最後刪除一個,分別查詢文件列表:
使用內部存儲的方式進行數據持久化,文件的地址將保存在/data/data/<package_name>/files/路徑下,上面創建了三個文件,最後刪掉了一個,如果是使用的模擬器,可以直接在File Explorer中查看:
緩存(cache)
既然提到了內部存儲,這裡再簡單的說說關於緩存文件(cache files)。cache files的操作與操作內部存儲中的文件方式基本一致,只是獲取文件的路徑有說不同。如果需要使用緩存的方式進行數據持久話,那麼需要使用Context.getCacheDir()方法獲取文件保存的路徑。
對於緩存文件而言,當設備內部內存存儲空間不足的時候,Android會有自動刪除的機制刪除這些緩存文件,用來恢復可用空間,所以對於緩存文件而言,內容一般最好控制在1MB之下,並且也不要存放重要的數據,因為很可能下次去取數據的時候,已經被Android系統自動清理了。
External Storage
使用外部存儲實現數據持久化,這裡的外部存儲一般就是指的是sdcard。使用sdcard存儲的數據,不限制只有本應用訪問,任何可以有訪問Sdcard權限的應用均可以訪問,而Sdcard相對於設備的內部存儲空間而言,會大很多,所以一般比較大的數據,均會存放在外部存儲中。
使用SdCard存儲數據的方式與內部存儲的方式基本一致,但是有三點需要注意的:
因為訪問Sdcard的方式和訪問內部存儲的方式差不多,這裡就展示一個Save的方法,用於保存文件,其他CRUD操作,這裡就不再一一給出了。
- public void saveToSdcard(String filename, String content) throws IOException {
- if (Environment.MEDIA_MOUNTED.equals(Environment
- .getExternalStorageState())) {
- Log.i("main", "本設備有存儲卡!");
- File file = new File(Environment.getExternalStorageDirectory(),
- filename);
- FileOutputStream fos = null;
- fos = new FileOutputStream(file);
- fos.write(content.getBytes());
- fos.close();
- }
- }
而如果使用SdCard存儲文件的話,存放的路徑在Sdcard的根目錄下,如果使用模擬器運行程序的話,創建的文件在/mnt/sdcard/目錄下:
補充:對於現在市面上很多Android設備,自帶了一個大的存儲空間,一般是8GB或16GB,並且又支持了Sdcard擴展,對於這樣的設備,使用Enviroment.getExternalStorageDirectory()方法只能獲取到設備自帶的存儲空間,對於另外擴展的Sdcard而言,需要修改路徑。
源碼下載
總結
以上就介紹了內部存儲、外部存儲、緩存存儲的方式方法。開發者可以根據需要選擇不同的方式進行數據持久化。
在項目開發中,可能系統自帶的一些widget不能滿足我們的需求,這時就需要自定義View。 通過查看系統中的常用widget如Button,TextView,Ed
Android的事件分發和處理方式 對android開發有一定了解的同學一定或多或少知道android的觸摸事件分發,整個事件的分發消耗流程都可以
這篇文章主要為大家詳細介紹了Android系統模擬位置的使用方法,具有參考價值,感興趣的小伙伴們可以參考一下 本文為大家分享了Andro
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我