1. 程式人生 > >Android的資料儲存方案

Android的資料儲存方案

1、概述

android中的資料是有許可權控制的,應用軟體資料為該應用軟體所私有的。但是android也提供了一種標準的方式將軟體的私有資料開放給其他應用軟體。
android可供選擇的儲存方式:sharedPreferences、檔案儲存、SQLite資料庫方式、內容提供器(Content provider)和網路儲存。


2、sharedPreferences

sharedPreferences是一種輕量型的資料儲存方式,本質上是基於XML檔案儲存key-value鍵值對資料,通常用來儲存一些簡單的配置資訊。sharedPreferences物件本身只能獲取資料而不支援儲存和修改,儲存修改是通過Editor物件實現的。(檔案一般存放在/data/data/<包名>/shared_prefs

目錄下,只能在file explorer中看)
實現sharedPreferences儲存的步驟為:
。根據Context獲取sharedPreferences物件;
。利用edit()方法獲取Editor物件(確保資料值是一致性的狀態,並且控制所有的值都已經提交儲存了);
。通過Editor物件儲存key-value鍵值對資料;
。通過commit()方法提交資料
sharedPreferences比之於sqlLite資料庫,免去了資料庫方面的操作,更加的方便簡潔。但是缺點就是隻能儲存boolean,int,float,long和String五種簡單的資料型別,並且無法進行條件查詢等。隨意sharedPreferences只是一種補充方式。

private void doStore() {
   // get the object of SharedPreferences
   Context ctx = DataStoreActivity.this;
   SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE);
   // store into values
   Editor editor = sp.edit();
   editor.putString("STRING_KEY", "string");        
   editor.putInt("INT_KEY", 0);
   editor.putBoolean("BOOLEAN_KEY", true);
   editor.commit();
   //read it	
   Log.d("SP", sp.getString("STRING_KEY", "none"));
   Log.d("SP", sp.getString("NOT_EXIST", "none"));
}


3、檔案儲存

android的檔案操作和java中實現I/O的方式是類似的,其提供了openFileInput()和openFileOutput()方法來寫入和讀取裝置上的檔案。

FileOutputStream fos = ctx.openFileOutput("file_name", MODE_PRIVATE);  //寫入
FileInputStream fis = ctx.openFileInput("file_name");  //讀取

這兩個方法只支援讀取該應用目錄下的檔案,讀取非自身目錄下的檔案將會丟擲異常。不存在操作的檔案,系統會在寫入的時候自動建立(建立的檔案一般儲存在/data/data/<包名>/files目錄下)。
預設情況下,使用openFileOutput方法建立的檔案只能被其呼叫的應用使用,其他應用無法讀取這個檔案。如果需要在不同應用中的共享,可以使用Content Provider實現這個功能。

// 寫入檔案
FileOutputStream fos = openFileOutput("test", MODE_WORLD_READABLE);
fos.write(text.getText().toString().getBytes());

// 讀取
FileInputStream fis = openFileInput("test");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = -1;
while ((length=fis.read(buffer)) != -1) {
	stream.write(buffer);
}
text.setText(stream.toString());

activity還提供了getCacheDir()和getFilesDir()方法:
。getCacheDir()方法用於獲取/data/data/<package name>/cache目錄
。getFilesDir()方法用於獲取/data/data/<package name>/files目錄

上面的操作都是將資料儲存到手機記憶體或從手機記憶體讀取資料,那怎麼操作SD卡呢?

首先要在建立一張SDCard(映象檔案),建立SDCard可以再eclipse建立模擬器時同時建立,也可以使用dos命令【mksdcard -l mycard 20M F:\mysdcard.img】進行建立。
再就是需要為訪問SDCard申請許可權,如下:

<!-- 在SDCard中建立與刪除檔案許可權 --> 
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 

<!-- 往SDCard寫入資料許可權 --> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

要往sdcard存放檔案,程式必須先判斷手機是否裝有sdcard,並且可以進行讀寫。

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 
    File sdCardDir = Environment.getExternalStorageDirectory();//獲取SDCard目錄 
     File saveFile = new File(sdCardDir, “a.txt”); 
    FileOutputStream outStream = new FileOutputStream(saveFile);
    outStream.write("test".getBytes()); 
    outStream.close(); 
} 

Environment.getExternalStorageState():用於獲取sdcard的狀態,如果手機裝有sdcard,並且可以進行讀寫,那麼返回的狀態就等於Environment.MEDIA_MOUNTED。
Environment.getExternalStorageDirectory():用於獲取sdcard獲取的目錄,等價於:

File sdCardDir = new File("/sdcard"); //獲取SDCard目錄 


4、Environment類

static File

static File

(String type)  Get a top-level public external storage directory for placing files of a particular type(根據檔案的類別放到想要放到的地方).

static File

5、SQLLite儲存方式

sqllite是一種輕型資料庫,只支援五種資料型別,分別是:NULL(空值)、INTEGER(整數)、REAL(浮點數)、TEXT(字串)、BLOB(大資料)。
1)建立資料庫:openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory) 根據給定條件連線資料庫,如果此資料庫不存在,則建立。

SQLiteDatabase db = this.openOrCreateDatabase("test_db.db", Context.MODE_PRIVATE, null);
SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase("/data/data/com.test/databases/test_db2.db3", null);

兩種方式建立資料庫,this.openOrCreateDatabase其實是根據SQLiteDatabase.openOrCreateDatabase而來的,SQLiteDatabase.openOrCreateDatabase()方法第一個引數要求輸入絕對路徑(所有的資料庫都是儲存在/data/data/<包名>/databases目錄下);而採用this.openOrCreateDatabase()可以不用使用絕對路勁。

2)建立資料表:execSQL(String sql)— 執行給定SQL語句。

db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");

execSQL()可以之人任何的sql語句。

3)CUID:insert、delete、update、query(rawQuery)

db.insert(String table, String nullColumnHack, ContentValues values);  
db.update(String table, Contentvalues values, String whereClause, String whereArgs);  
db.delete(String table, String whereClause, String whereArgs);  

三個方法的第一個引數都是要進行操作的表名;
insert的第二個引數表示如果插入了一行空資料時,需要指定某一列的名稱,系統將此列設定為NULL,否則會報錯,第三個引數是ContentValues型別的變數,類似於鍵值對的Map,key代表列名,value代表值;
update的第二個ContentValues,更新該欄位key為最新的value值,第三個引數whereClause表示WHERE表示式,比如"age > ? and age < ?”等,最後的whereArgs引數是佔位符的實際引數值;
delete的引數和update是類似的;

db.rawQuery(String sql, String[] selectionArgs);  
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);  
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);  
db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 

上面幾種都是常用的查詢方法,第一種最為簡單,將所有的SQL語句都組織到一個字串中,使用佔位符代替實際引數,selectionArgs就是佔位符實際引數集;下面的幾種引數都很類似,columns表示要查詢的列所有名稱集,selection表示WHERE之後的條件語句,可以使用佔位符,groupBy指定分組的列名,having指定分組條件,配合groupBy使用,orderBy指定排序的列名,limit指定分頁引數,distinct可以指定“true”或“false”表示要不要過濾重複值。需要注意的是,selection、groupBy、having、orderBy、limit這幾個引數中不包括"WHERE”、"GROUP BY”、"HAVING”、"ORDER BY”、"LIMIT”等SQL關鍵字。

4)cursor操作

c.move(int offset); //以當前位置為參考,移動到指定行  
c.moveToFirst();    //移動到第一行  
c.moveToLast();     //移動到最後一行  
c.moveToPosition(int position); //移動到指定行  
c.moveToPrevious(); //移動到前一行  
c.moveToNext();     //移動到下一行  
c.isFirst();        //是否指向第一條  
c.isLast();     //是否指向最後一條  
c.isBeforeFirst();  //是否指向第一條之前  
c.isAfterLast();    //是否指向最後一條之後  
c.isNull(int columnIndex);  //指定列是否為空(列基數為0)  
c.isClosed();       //遊標是否已關閉  
c.getCount();       //總資料項數  
c.getPosition();    //返回當前遊標所指向的行數  
c.getColumnIndex(String columnName);//返回某列名對應的列索引值  
c.getString(int columnIndex);   //返回當前行指定列的值  


完整的例項:

protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
          
    //開啟或建立test.db資料庫  
     SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);  
    db.execSQL("DROP TABLE IF EXISTS person");  
    //建立person表  
     db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)");  
    Person person = new Person();  
    person.name = "john";  
    person.age = 30;  
    //插入資料  
     db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age});  
          
     person.name = "david";  
     person.age = 33;  
     //ContentValues以鍵值對的形式存放資料  
      ContentValues cv = new ContentValues();  
     cv.put("name", person.name);  
     cv.put("age", person.age);  
     //插入ContentValues中的資料  
      db.insert("person", null, cv);  
          
     cv = new ContentValues();  
     cv.put("age", 35);  
     //更新資料  
      db.update("person", cv, "name = ?", new String[]{"john"});  
          
     Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"});  
     while (c.moveToNext()) {  
        int _id = c.getInt(c.getColumnIndex("_id"));  
        String name = c.getString(c.getColumnIndex("name"));  
        int age = c.getInt(c.getColumnIndex("age"));  
        Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age);  
     }  
        c.close();  
          
     //刪除資料  
      db.delete("person", "age < ?", new String[]{"35"});  
          
     //關閉當前資料庫  
      db.close();  
          
     //刪除test.db資料庫  
     deleteDatabase("test.db");  
}  


6、SQLiteOpenHelper

幫助管理資料庫的建立和版本的管理。要使用它必須實現它的onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)方法。
onCreate:當資料庫第一次被建立的時候被執行;
onUpgrade:當資料庫需要被更新的時候執行,如資料庫版本的變更;
還可以根據實際情況實現onOpen()等方法。

7、ContentProvider

android系統的資料時私有的,包括檔案資料和資料庫資料,兩個程式之間無法進行資料的交換。ContentProvider實現了一組標準的方法介面,從而能夠讓其他的應用儲存或讀取此Content Provider的各種資料型別。就是說,一個程式可以通過實現一個Content Provider的抽象介面將自己的資料暴露出去,外部可以訪問。步驟為:
1)在當前應用程式中實現一個Content Provider
2)在當前應用程式的AndroidManifest.xml中註冊此Content Provider
3)其他程式通過ContentResolver和Uri來獲取此Content Provider的資料


3、Handler

Handler主要負責傳送和處理訊息,用途:
。按計劃傳送訊息或執行某個執行緒;
。從其他執行緒中傳送來的訊息放入訊息佇列中,避免執行緒衝突;