Android資料的四種儲存方式

來源:互聯網
上載者:User

標籤:

很清晰的思路,轉自Android資料的四種儲存方式

作為一個完成的應用程式,資料存放區操作是必不可少的。因此,Android系統一共提供了四種資料存放區方式。分別是:SharePreference、SQLite、Content Provider和File。由於Android系統中,資料基本都是私人的的,都是存放於“data/data/程式包名”目錄下,所以要實現資料共用,正確方式是使用Content Provider。

  SQLite: SQLite是一個輕量級的資料庫,支援基本SQL文法,是常被採用的一種資料存放區方式。Android為此資料庫提供了一個名為SQLiteDatabase的類,封裝了一些操作資料庫的API。

  SharedPreference: 除SQLite資料庫外,另一種常用的資料存放區方式,其本質就是一個xml檔案,常用於儲存較簡單的參數設定。

  File: 即常說的檔案(I/O)儲存方法,常用語儲存大數量的資料,但是缺點是更新資料將是一件困難的事情。

  ContentProvider: Android系統中能實現所有應用程式共用的一種資料存放區方式,由於資料通常在各應用間的是互相私密的,所以此儲存方式較少使用,但是其又是必不可少的一種儲存方式。例如音頻,視頻,圖片和通訊錄,一般都可以採用此種方式進行儲存。每個Content Provider都會對外提供一個公用的URI(封裝成Uri對象),如果應用程式有資料需要共用時,就需要使用Content Provider為這些資料定義一個URI,然後其他的應用程式就通過Content Provider傳入這個URI來對資料進行操作。

 

  SQLite是一種轉為嵌入式裝置設計的輕型資料庫,其只有五種資料類型,分別是:

    NULL:      空值

    INTEGER: 整數

    REAL:      浮點數

    TEXT:      字串

    BLOB:     大資料

  在SQLite中,並沒有專門設計BOOLEAN和DATE類型,因為BOOLEAN型可以用INTEGER的0和1代替true和false,而DATE類型則可以擁有特定格式的TEXT、REAL和INTEGER的值來代替顯示,為了能方便的操作DATE類型,SQLite提供了一組函數,詳見:http://www.sqlite.org/lang_datefunc.html。這樣簡單的資料類型設計更加符合嵌入式裝置的要求。關於SQLite的更多資料,請參看:http://www.sqlite.org/

  在Android系統中提供了android.database.sqlite包,用於進行SQLite資料庫的增、刪、改、查工作。其主要方法如下:

  beginTransaction():                 開始一個事務。

  close():                                  關閉串連,釋放資源。

  delete(String table, String whereClause, String[] whereArgs):      根據給定條件,刪除合格記錄。

  endTransaction():                   結束一個事務。

  execSQL(String sql):               執行給定SQL語句。

  insert(String table, String nullColumnHack, ContentValues values):                根據給定條件,插入一條記錄。 

  openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory): 根據給定條件串連資料庫,如果此資料庫不存在,則建立。

  query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy): 執行查詢。

  rawQuery(String sql, String[] selectionArgs):                                               根據給定SQL,執行查詢。

  update(String table, ContentValues values, String whereClause, String[] whereArgs):     根據給定條件,修改合格記錄。

  除了上訴主要方法外,Android還提供了諸多實用的方法,總之一句話:其實Android訪問資料庫是一件很方便的事兒。

  一、 建立資料庫

  通過openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory)方法建立資料庫。    

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

  如上兩種方式均能建立資料庫,this.openOrCreateDatabase是對SQLiteDatabase.openOrCreateDatabase而來,如代碼所見,原生的SQLiteDatabase.openOrCreateDatabase()方法第一參數要求輸入絕對路勁,而所有的資料庫都是儲存於“data/data/應用報名/databases”目錄下,所以輸入完全的絕對路勁是一件重複且繁雜的工作。採用this.openOrCreateDatabase則省去了此操作。執行操作後的結果如:  

 

  另外還可以通過寫一個繼承SQLiteOpenHelper類的方式建立資料庫,此種方式是一種更加進階的建立方式,所以在此不做描述。

  二、建立資料表,插入資料。

  Android系統並沒有提供特別的建立資料表的方法,資料表通過SQL語句建立,代碼如下:

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

  表建立好之後,通過insert(String table, String nullColumnHack, ContentValues values)方法插入資料,其中參數含義分別為:

    table: 目標表名

    nullColumnHack: 指定表中的某列列名。因為在SQLite中,不允許不允許插入所有列均為null的記錄,因此初始值有值為空白時,此列需顯式賦予null

    values: ContentValues對象,類似於java中的Map。以索引值對的方式儲存資料。

  資料插入代碼如下: 

1  ContentValues values =new ContentValues();
2 for(int i=0;i<10;i++){
3 values.put("name", "test"+ i);
4 db.insert("tab", "_id", values);
5 }

 

  執行此操作後,會新增一個名為“tab”的資料表,利用SQLite用戶端(推薦:SQLite Expert Personal 3)可輕鬆查看此表結構和資料。如:

  

  三、修改資料

   update(String table, ContentValues values, String whereClause, String[] whereArgs)方法用於修改資料,其四個參數的具體含義如下:

    table:    目標表名

    values:  要被修改成為的新值

    whereClause:    where子句,除去where關鍵字剩下的部分,其中可帶?預留位置。如沒有子句,則為null。

    whereArgs:       用於替代whereClause參數中?預留位置的參數。如不需傳入參數,則為null。

  資料修改代碼如下:

1 ContentValues values =new ContentValues();
2 values.put("name", "name");
3 db.update("tab", values, "_id=1", null);
4 db.update("tab", values, "_id=?", new String[]{"5"});

 

  執行結果如,_id=1和_id=5的資料,name欄位的值被修改為了“name”。

  四、查詢資料。

  之前一直使用SQLite用戶端查看資料情況了,這裡就使用android提供的query()和rowQuery()方法執行查詢。具體代碼如下:  

 

 1 Cursor c = db.query("tab", null, null, null, null, null, null);
2 c.moveToFirst();
3 while(!c.isAfterLast()){
4 int index = c.getColumnIndex("name");
5 Log.d("SQLite", c.getString(index));
6 c.moveToNext();
7 }
8 c = db.rawQuery("select * from tab", null);
9 c.moveToFirst();
10 while(!c.isAfterLast()){
11 int index = c.getColumnIndex("name");
12 Log.d("SQLite", c.getString(index));
13 c.moveToNext();
14 }

  查詢結果如:

  可以清晰的在查詢結果中,紅線上下的資料是完全一致的,也就是說query和rawQuery方法在的不同僅僅在於所需參數的不同。rawQuery方法需要開發人員手動寫出查詢SQL,而query方法是由目標表名、where子句、order by子句、having子句等諸多子句由系統組成SQL語句。兩方法同返回Cursor對象,所以兩方在使用時孰優孰劣,就看具體情況了。本人更喜歡rawQuery的方式,因為此方式更接近傳統Java開發,也可以由專業DBA來書寫SQL語句,這樣更符合MVC的思想,而且這樣的代碼可讀性更高。(query方法裡面參數實在太多,有點記不住誰是order by子句,誰是having子句了)

  Cursor對象可以理解為遊標對象,凡是對資料有所瞭解的人,相信對此對象都不會陌生,在這裡機不再累述。只提醒一點,在第一次讀取Cursor對象中的資料時,一定要先移動遊標,否則此遊標的位置在第一條記錄之前,會引發異常。

  五、刪除資料

  刪除資料也是一件很簡單的事,只需要調用delete方法,傳入參數即可,delete(String table, String whereClause, String[] whereArgs)的參數三個參數具體含義如下:

    table:             目標表名

    whereClause:  where子句,除去where關鍵字剩下的部分,其中可帶?預留位置。如沒有子句,則為null。

         whereArgs:     用於替代whereClause參數中?預留位置的參數。如不需傳入參數,則為null。

 

  具體代碼如下:

db.delete("tab", "_id=? or name=?", new String[]{"8", "name"});

 

  執行結果如下:

 

 

  其中_id=8和name=‘name’的資料統統被刪除了。

  整個資料庫的CRUD操作到此示範完了。最後提醒一點,在操作完資料後,一定要記得調用close()方法關閉串連,釋放資源。這個原因相信大家都是懂的。

 

 

         SharedPreferences也是一種輕型的資料存放區方式,它的本質是基於XML檔案儲存體key-value索引值對資料,通常用來儲存一些簡單的配置資訊。其儲存位置在/data/data/<包名>/shared_prefs目錄下。SharedPreferences對象本身只能擷取資料而不支援儲存和修改,儲存修改是通過Editor對象實現。實現SharedPreferences儲存的步驟如下:

  一、根據Context擷取SharedPreferences對象

  二、利用edit()方法擷取Editor對象。

  三、通過EditorObject Storage Servicekey-value索引值對資料。

  四、通過commit()方法提交資料。

  具體實現代碼如下:

 1 publicclass MainActivity extends Activity {
2 @Override
3 publicvoid onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 setContentView(R.layout.main);
6
7 //擷取SharedPreferences對象
8 Context ctx = MainActivity.this;
9 SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE);
10 //存入資料
11 Editor editor = sp.edit();
12 editor.putString("STRING_KEY", "string");
13 editor.putInt("INT_KEY", 0);
14 editor.putBoolean("BOOLEAN_KEY", true);
15 editor.commit();
16
17 //返回STRING_KEY的值
18 Log.d("SP", sp.getString("STRING_KEY", "none"));
19 //如果NOT_EXIST不存在,則傳回值為"none"
20 Log.d("SP", sp.getString("NOT_EXIST", "none"));
21 }
22 }

   這段代碼執行過後,即在/data/data/com.test/shared_prefs目錄下產生了一個SP.xml檔案,一個應用可以建立多個這樣的xml檔案。: 

   SP.xml檔案的具體內容如下:

1 <?xml version=‘1.0‘ encoding=‘utf-8‘ standalone=‘yes‘ ?>
2 <map>
3 <string name="STRING_KEY">string</string>
4 <int name="INT_KEY" value="0"/>
5 <boolean name="BOOLEAN_KEY" value="true"/>
6 </map>

  在程式碼中,通過getXXX方法,可以方便的獲得對應Key的Value值,如果key值錯誤或者此key無對應value值,SharedPreferences提供了一個賦予預設值的機會,以此保證程式的健壯性。如運行結果中因為並無值為"NOT_EXIST"的Key,所以Log列印出的是其預設值:“none”。在訪問一個不存在key值這個過程中,並無任何異常拋出。  

  SharedPreferences對象與SQLite資料庫相比,免去了建立資料庫,建立表,寫SQL語句等諸多操作,相對而言更加方便,簡潔。但是SharedPreferences也有其自身缺陷,比如其職能儲存boolean,int,float,long和String五種簡單的資料類型,比如其無法進行條件查詢等。所以不論SharedPreferences的資料存放區操作是如何簡單,它也只能是儲存方式的一種補充,而無法完全替代如SQLite資料庫這樣的其他資料存放區方式。

 

        ContentProvider是Android平台中,在不同應用程式之間實現資料共用的一種機制。一個應用程式如果需要讓別的程式可以操作自己的資料,即可採用這種機制。並且此種方式忽略了底層的資料存放區實現,ContentProvider提供了一種統一的通過Uri實現資料操作的方式。其步驟為:

  1. 在當前應用程式中定義一個ContentProvider。

  2. 在當前應用程式的AndroidManifest.xml中註冊此ContentProvider

  3. 其他應用程式通過ContentResolver和Uri來擷取此ContentProvider的資料。

 

  ContentResolver提供了諸如insert(), delete(), query()和update()之類的方法。用於實現對ContentProvider中資料的存取操作。

  Uri是一個通用資源標誌符,將其分為A,B,C,D 4個部分:

    A:無法改變的標準首碼,包括;"content://"、"tel://"等。當首碼是"content://"時,說明通過一個Content Provider控制這些資料  

    B:URI的標識,它通過authorities屬性聲明,用於定義了是哪個ContentProvider提供這些資料。對於第三方應用程式,為了保證URI標識的唯一性,它必須是一個完整的、小寫   類名。例如;"content://com.test.data.myprovider"  

    C:路徑,可以近似的理解為需要操作的資料庫中表的名字,如:"content://hx.android.text.myprovider/name"中的name

    D:如果URI中包含表示需要擷取的記錄的ID;則就返回該id對應的資料,如果沒有ID,就表示返回全部;

 

  下面通過是程式碼範例,示範一下如何在應用之間相互擷取資料。

  在應用程式A中,繼承ContProvider類,並重寫其中方法。

 1 publicclass MyProvider extends ContentProvider{
2 @Override
3 publicint delete(Uri uri, String selection, String[] selectionArgs) {
4 // TODO Auto-generated method stub
5 return0;
6 }
7
8 @Override
9 public String getType(Uri uri) {
10 // TODO Auto-generated method stub
11 returnnull;
12 }
13
14 @Override
15 public Uri insert(Uri uri, ContentValues values) {
16 returnnull;
17 }
18
19 //在Create中初始化一個資料庫
20 @Override
21 publicboolean onCreate() {
22 SQLiteDatabase db =this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
23 db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
24 ContentValues values =new ContentValues();
25 values.put("name", "test");
26 db.insert("tab", "_id", values);
27 db.close();
28 returntrue;
29 }
30
31 //實現query方法
32 @Override
33 public Cursor query(Uri uri, String[] projection, String selection,
34 String[] selectionArgs, String sortOrder) {
35 SQLiteDatabase db =this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
36 Cursor c = db.query("tab", null, null, null, null, null,null);
37 return c;
38 }
39
40 @Override
41 publicint update(Uri uri, ContentValues values, String selection,
42 String[] selectionArgs) {
43 // TODO Auto-generated method stub
44 return0;
45 }
46 }

  在其AndroidManifest.xml中聲明此ContentProvider,其中authorities屬性定義了此ContentProvider的Uri標識。

<provider android:name=".MyProvider" android:authorities="com.test.MyProvider"/>

  在應用程式B中,通過ContentResolver擷取程式A的ContentProvider中的資料。

 1 publicclass MainActivity extends Activity {
2 @Override
3 publicvoid onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 setContentView(R.layout.main);
6
7 //擷取上下文
8 Context ctx = MainActivity.this;
9 //擷取ContentResolver對象
10 ContentResolver resolver = ctx.getContentResolver();
11 //擷取Uri對象
12 Uri uri = Uri.parse("content://com.test.MyProvider");
13 //擷取資料
14 Cursor c = resolver.query(uri, null, null, null, null);
15 c.moveToFirst();
16 for(int i=0; i<c.getCount(); i++){
17 int index = c.getColumnIndexOrThrow("name");
18 String src = c.getString(index);
19 Log.d("", src);
20 c.moveToNext();
21 }
22 }
23 }

  應用程式B的運行結果如下,從此圖可以發現我們在程式B中成功的擷取到了程式A中的資料:

  再觀察兩個應用程式的結構,如,其中紅框是應用程式A的程式結構,可以清楚看到其有一個名為“test_db.db3”的資料庫,藍框是應用程式B的程式結構,其並沒有任何資料庫用於儲存資料。由此圖,可以確定應用程式B中查詢出來的資料結果是來自於應用程式A。

  以上就是ContentProvider的使用方式,這種儲存方式相比SQLite和SharedPreferences,其複雜性是顯而易見的,但是在處處可見“雲”的今天,程式間的資料互動需求令ContentProvider儲存機制變成必不可少的一部分。

Android資料的四種儲存方式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.