在Android中,提供了三種數據存儲的途徑,和兩種存儲方式。
三種途徑:
l 系統配置(Shared Preferences):
這類應用主要是系統的配置信息的保存,比如我給程序界面設置了顏色,我想在下一次啓動時還是能夠保留上次設置的顏色。由於Android系統的界面是採用Activity棧的形式,在系統資源不足時,會收回一些界面,那麼,我想有些操作也是需要在不活動時保留下來的,等再次激活時能夠顯示出來。
l 文件(Files)
Android是一個操作系統,自然而然對存儲系統會有一個管理,因爲採用提Linux核心,所有在Andorid系統中,文件也是Linux的形式。當然我們的應用程序也就可以把數據以文件的形式記錄下來咯。
l 數據庫(SQLite Databases)
在Andriod系統中,也少不了一個數據庫管理,但考慮到系統資源(內存,硬盤),選擇了輕便型的數據庫SQLite,這是一個開源的關係型數據庫,與普通關係型數據庫一樣,也具有ACID的特性。
兩種存儲方式:
主要是根據數據庫共享方式來分
l 程序內自用:
通常我們程序中需要的數據一般都是爲本程序來用,所以我們用上面三種途徑來創建的程序都是默認爲本程序使用,其他程序無法獲取操作。
我們ADB插件功能在命令行下輸入:adb shell 來進入手機的文件系統,進入CD /data/data目錄。然後ls查看,我們發現,我們在系統中安裝的每個程序在這裏都有一個文件夾,再次進入我們的程序後ls查看,會出現幾個目錄:shared_prefs、files、databases,這幾個目錄其實就是存的我們程序內自用的數據,內容分別就是由上面三種途徑創建的,當然如果沒有創建過,這個目錄可能不存在。
l 數據需要共享:
這類數據通常是我們的一些共用數據,很多程序都會來調用,比如電話薄數據,就不可能存爲私有的了。當然,這種方式的話,上面三種途徑中的系統配置就不適用了,“系統配置”只能由本程序訪問。也就是說,只有文件和數據庫可以共享。
具體用沒我們下面依次試一下:
(一)系統配置
這類數據存儲形式是NVP形式即,name和value的映射map。
存:
// 取得活動的preferences對象.
SharedPreferences uiState = getPreferences(0);
// 取得編輯對象
SharedPreferences.Editor editor = uiState.edit();
// 添加值
editor.putString(KEY, value);
editor.putBoolean(KEY, value);
editor.commit();//提交保存.
取:
//取得活動的preferences對象.
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
// 取得值.
String value = settings.getString(KEY, "默認值");
Boolean value = settings.getBoolean(KEY, false);
存取時間:
有了存取的方法後,我們就要想在什麼時候來存取:
protected void onPause()//系統通知暫停,可以保存設置
public void onDestroy()//系統通知關閉,可以保存設置
public void onCreate(Bundle savedInstanceState) //系統啓動,可以打開設置
同樣還有其他狀態,我們可以根據實際情況來處理
(二)文件操作
l 打開文件並可操作,如果文件不存在會自動創建:
FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
//操作時,在fos裏寫入值即可
l 讀文件:
FileInputStream fis = openFileInput(FILE_NAME);
l 取得當前活動創建的文件列表:
String[] lst =fileList()
l 刪除文件:
super.deleteFile(FILE_NAME);
(三)SQLite數據庫操作
數據庫操作無非是建庫、建表、增、刪、改、查的一些常用功能。在Android系統中封裝了一個SQLiteDatabase類,用於這些操作。
l 建庫
創建數據庫,是由SQLiteOpenHelper類自動完成,同時,創建後,會返回一個SQLiteDatabase類:
try {
SQLiteOpenHelper dbHelper= new SQLiteOpenHelper(context,DBName,null,1);
db = dbHelper.getWritableDatabase();
} catch (SQLiteException ex) {
db = dbHelper.getReadableDatabase();
}
其中參數DBName就是數據庫的名稱。getWritableDatabase(),這方法就會獲取數據庫對象,如果庫不存在就會新建,但這裏爲什麼還要包一層catch呢,主要考慮到,手機的資源有限,有時空間不足了,就無法再寫入數據,但這裏我們可以讀啊,所以在catch中調用了getReadableDatabase。
l 建表
_db.execSQL(“create table tableName (id integer primary key autoincrement,name text not null);”);
看到,這個建表其實跟我們寫的SQL很類似,只是可能一些語法細節不同,具體這個就不寫了,google一下會N多了。
l 增
當然我們可以執行一條SQL語句來插入,我們也可以這樣來:
ContentValues newTaskValues = new ContentValues();
// Assign values for each row.
newTaskValues.put(KEY_TASK, value);
newTaskValues.put(KEY_CREATION_DATE, value);
// Insert the row.
db.insert(DATABASE_TABLE, null, newTaskValues);
我們可以將值依次放入一個Hash表中,然後直接存入。
l 刪
db.delete(tableName, "id=" + _rowIndex, null)
輸入表名,以及條件,當然,直接拼成一條標準SQL也是可以的。
l 改
ContentValues newValue = new ContentValues();
newValue.put(KEY_TASK, _task);
db.update(DATABASE_TABLE, newValue, KEY_ID + "=" + _rowIndex, null
將值存於Hash表中,再直接調用
l 查
Cursor result =db.query(DATABASE_TABLE,
new String[] { KEY_ID, KEY_TASK, KEY_CREATION_DATE},
null, 條件, null, null, null)
這裏,查詢後返回的是一個遊標,我們可以通過這遊標來獲取數據,使用方法跟java通用程序一樣。
還有更多的用法,只有邊用邊再搜Google了
(四)Content Providers共享數據
在前面界面交互中,我們也學習到了,Android系統的界面互相調用時,傳值是採用Uri的方式進行的。表面上看,Uri不就是一個字符串嗎,能傳多少值啊,其實不然,在Uri中格式:(1)://(2)/(3),這第一段我們不管,這第二段,其實在系統中是可以定義到我們的Content Providers的,我們可以寫一個類,比如這個用來管理電話薄信息,如:
public class MyProvider extends ContentProvider {
private static final String myURI =
"content://com.zjf.MyProvider/items";
public static final Uri CONTENT_URI = Uri.parse(myURI);
…
}
在這裏MyProvider繼承了ContentProvider類,然後我們在系統中註冊一下(在manifext.xml中):
<provider android:name=”MyProvider”android:authorities=” com.zjf.MyProvider”/>
然後我們在傳值時使用:content://com.zjf.MyProvider/1來通過這個Uri我想得到電話薄中第一個人的信息,我們分析一下,這個最後一段“1”,就是第一個記錄咯,“com.zjf.MyProvider”這個就是標記我用哪一套程序來取數據,所以說,我們寫的MyProvider就可以根據傳入的“1”這個參數來進行數據的操作,這裏你可以保存到文件中,也可以保存到數據庫中,但對使用者來說是透明的,不需要知道內部細節。這就是我們說的數據共享模型。
我們進一步看MyProvider繼承處理了哪些類:
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
@Override
public Uri insert(Uri uri, ContentValues values)
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
看到這些大家可能就更家明白了MyProvider就是一個數據的封裝,它按照統一的接口來提供共享的數據,每一個Provider就是處理一類共享數據。
當然系統中其實己經供了這樣的一些Provider供我們來使用,比如:Browser記錄了用戶瀏覽記錄;CallLog記錄系統日誌;Contacts電話薄;Settings系統設置等。
看到這個不知大家有沒有想到我們前面取得電話薄信息時是不是用的“content:// Contacts/1”這樣的Uri,對應起來咯。
看了具體的Provider的實現,我們又想到,那這個統一的數據接口標準到底能提供我們哪些功能呢,其實看了Provider內部實現,我們也發現了,不就也就是增、刪、改、查麼。對,我們可能通過統一的接口來對這公用數據進行這些操作。具體方法如下:
查詢:
Cursor someRows = getContentResolver().query(MyProvider.CONTENT_URI,
null, where, null, order);
插入:
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
newValues.put(COLUMN_NAME, newValue);
Uri myRowUri = getContentResolver().insert(MyProvider.CONTENT_URI,newValues);
刪除:
getContentResolver().delete(MyProvider.CONTENT_URI, where, null);
修改:
getContentResolver().update(MyProvider.CONTENT_URI, newValues, where,
null);
這些幾個功能可以有點難理解,我們看個應用吧:
我想查詢電話薄中姓陳的人的信息,然後再刪除:
Cursor someRows = getContentResolver().query(“content:// Contacts”,
null, “name like ‘陳%’”, null, order);
//然後從遊標中獲取數據即可。
getContentResolver().delete(“content:// Contacts”, “name like ‘陳%’”, null);//刪除