Android的資料儲存方案
1、概述
android中的資料是有許可權控制的,應用軟體資料為該應用軟體所私有的。但是android也提供了一種標準的方式將軟體的私有資料開放給其他應用軟體。
android可供選擇的儲存方式:sharedPreferences、檔案儲存、SQLite資料庫方式、內容提供器(Content provider)和網路儲存。
2、sharedPreferences
sharedPreferences是一種輕量型的資料儲存方式,本質上是基於XML檔案儲存key-value鍵值對資料,通常用來儲存一些簡單的配置資訊。sharedPreferences物件本身只能獲取資料而不支援儲存和修改,儲存修改是通過Editor物件實現的。(檔案一般存放在/data/data/<包名>/shared_prefs
實現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主要負責傳送和處理訊息,用途:
。按計劃傳送訊息或執行某個執行緒;
。從其他執行緒中傳送來的訊息放入訊息佇列中,避免執行緒衝突;