1. 程式人生 > >Android資料的四種儲存方式----總結

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物件。

  三、通過Editor物件儲存key-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 stub11 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 stub44 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資料儲存方式----總結

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

Android儲存方式

插入資料:通過insert(String table, StringnullColumnHack, ContentValues values)方法插入資料,其中引數含義分別為:     table: 目標表名     nullColumnHack: 指定表中的某列列名。因為在SQLite中,不允許不允

IOS --Object-C 儲存資料方式

在iOS開發過程中,不管是做什麼應用,都會碰到資料儲存的問題。將資料儲存到本地,能夠讓程式的執行更加流暢,不會出現讓人厭惡的菊花形狀,使得使用者體驗更好。下面介紹一下資料儲存的方式: 1.NSKeyedArchiver:採用歸檔的形式來儲存資料,該資料物件需要遵守NSCoding協議,並且

Android佈局方式

線性佈局 <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orienta

JavaScript兩資料型別的儲存方式

JavaScript中資料型別的儲存 區別: 兩種型別的區別是:儲存位置不同 基本資料型別 原始資料型別是直接儲存在棧(stack)中的簡單資料段。因為佔據空間小、大小固定,屬於被頻繁使用資料,所以放入棧中儲存。 引用資料型別 引用資料型別儲存在堆(heap)中的物件,佔據空間大、大小不固定。如果

Android按鈕單擊事件的常用寫法總結

很多學習Android程式設計的人都會發現每個人對程式碼的寫法都有不同的偏好,比較明顯的就是對控制元件響應事件的寫法的不同。因此本文就把這些寫法總結一下,比較下各種寫法的優劣,希望對大家靈活地選擇編碼方式可以有一定的參考借鑑價值。 xml檔案程式碼如下: ? 1

Android開發之基本控制元件和詳解佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有F

Android開發的之基本控制元件和詳解佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有Frame絕對佈局和AutoL

Androidandroid開發之splash閃屏頁的實現方式,啟動頁的實現教程。

作者:程式設計師小冰,GitHub主頁:https://github.com/QQ986945193 首先給大家看一下今天實現的效果圖(其他三種都差不太多底下詳細介紹): 這個啟動頁實現的方法是四種,兩種是利用handler,其它兩種是利用了動畫的方式。 具體給大家貼一下

android提供的5儲存方式

一、最簡單的儲存SharedPreferences       SharedPreferences是Android提供用來儲存一些簡單的配置資訊的一種機制,它以鍵值對的方式儲存,經常用於儲存常見的歡迎語、登入使用者名稱和密碼等資訊。       SharedPreferen

Android activity啟動模式及taskAffinity屬性總結(附例子原始碼)

Android activity四種啟動模式總結本人目前在看 Android 開發藝術探索 這本書,書中對啟動模式的講解比較詳細,所以自己想總結下。如果各位能認真的看上一遍,相信會對android activity的啟動模式會有更加深刻的印象。Android啟動模式:   

Android實現計算器佈局(佈局方式)之TableLayout表格佈局

表格佈局:tablelayout table佈局不支援跨行跨列,所以主要佈局的思想就是表格巢狀 效果 outline 之前一直到不知道怎麼用表格實現計算器的佈局,查資料的時候也一直在考慮跨行跨列來實現,網上說table佈局不

資料的兩儲存方式 cookie 和 webstorage

什麼是cookie? 通俗的說就是當一個使用者通過HTTP協議訪問一個伺服器的時候,這個伺服器會將一些鍵值對(key:value)返回給客戶端瀏覽器,並在這些資料上加一些限制,在條件符合是,這個使用者下次訪問這個瀏覽器的時候,資料又被完整的待會給伺服器;cookie是瀏覽器

資料結構之圖的兩儲存方式

第一種:鄰接矩陣 鄰接矩陣可以表示頂點之間的相鄰關係的矩陣,是一個n階方陣,可以用一個一維陣列來表示頂點資訊,用一個二維陣列來表示頂點之間的邊的聯絡以及權重 具體的程式碼如下: #include <stdio.h> #inc

android執行緒間通訊的實現方式

1,通過Handler機制. private void one() { handler=new Handler(){ @Override

MYSQL儲存引擎的適用總結

如果要提供提交、回滾、崩潰恢復能力的事物安全(ACID相容)能力,並要求實現併發控制,InnoDB是一個好的選擇 如果資料表主要用來插入和查詢記錄,則MyISAM引擎能提供較高的處理效率 如果只是臨時存放資料,資料量不大,並且不需要較高的資料安全性,可以選擇將資料儲存在記

Android Notification 的使用方式

實現通知步驟 一般實現通知需要如下步驟: 1.獲取 NotificationManager 例項管理通知; 2.例項 Notification 物件; 3.管理事件 Intent; 4.傳送

Android Native C 之 Helloworld的編譯方式

一.編寫helloworld.c Android.mk     [[email protected] jni]# cat hello.c #include <stdio.h> int main() { printf("Hello World!

Android自定義控制元件:進度條的實現方式

Progress Wheel為GitHub熱門專案,作者是:Todd-Davies,專案地址: https://github.com/Todd-Davies/ProgressWheel 前三種實現方式程式碼出自: http://stormzhang.com/ope

5.6-全棧Java筆記:內部類的實現方式

java一般情況,我們把類定義成獨立的單元。有些情況下,我們把一個類放在另一個類的內部定義,稱為內部類(innerclasses)。內部類的作用1.內部類提供了更好的封裝。只能讓外部類直接訪問,不允許同一個包中的其他類直接訪問。2.內部類可以直接訪問外部類的私有屬性,內部類被當成其外部類的成員。 但外部類不能