Understanding Android ContentProvider

來源:互聯網
上載者:User
1. 什麼是ContentProvider

也即內容提供者,是對所有資料訪問的一層抽象,為資料訪問提供了統一的介面。它有以下優點:

a. 對資料的抽象,為所有的組件提供統一的訪問資料的方式,從而讓組件不必關心具體資料的呈現形式(檔案or資料庫)。資料,也可以只關心自身的管理,而不用去管使用者的訪問問題。這樣就達到了很好的封裝。

b. 介面更加方便,更加方便的讓組件之間傳送資料
ContentProvider的訪問標識為Uri,通過統一的ContentResolver進行訪問,而ContentResolver和Uri跟Application的上下文Context以及組件之間的資訊傳送工具Intent都是無縫接合,這就讓組件之間進行資料共用和資料傳遞更加的方便和快捷。
所以,ContentProvider的最大好處在於它可以在不同組件之間方便的共用。所以,如果你的應用裡面用到的資料需要在不同的組件之間共用,那麼實現一個ContentProvider無疑是最佳方案。

2. 實現方式

ContentProvider的實現方式非常簡單,只需要根據需求實現一些介面即可,比如:query, insert, delete, update, openFile等。但是具體的資料的呈現形式則是根據不同的目的進行自由選擇,比如對於結構化資料,選擇SQLiteDatabase可能是比較好的方案,大量的位元組流可能檔案是首選等等。
需要注意一點的是,雖然Android中百分之九十的ContentProvider內部都是用SQLiteDatabase來儲存結構化資料,但這並不意味著ContentProvider只能從SQLiteDatabase來管理資料。ContentProvider定義了一些介面,你只需要按照需要返回正確的資料即可,具體 的實現方式則由你自由選擇。
比如,Contacts的ContentProvider能提供以vCard的方式輸出,也就是說當讀取一個vCard的uri時,這個流是一個vCard形式的檔案流,實現起來的思路就是這樣:
Cursor query(Uri, ....) {
   if (uri is for vCard) {
       query the Contact's infomation
       create a cursor with two columns name and size
       put contact's name into cursor
       sum all Contact's field  and get size
       put that size into cursor
       return the cursor
   }
}
這樣通過Query就能得到這個vCard的相關資訊檔名字和大小,再通過openInputStream就可以讀取這個vCard檔案流,但是實際上ContentProvider是沒有vCard形式的資料,也沒有一個vCard的檔案,它只是在openFile的時候,識別出vCard的uri,把Contact資料轉化成vCard形式寫入輸出資料流中:
ParcelFileDescriptor openFile(Uri...) {
    if (uri is for vcard) {
       generate vcard with VCardComposer
       write to output stream
    }
}

3. 其他替代方案

ContentProvider不是必須的,每個應用必然用到資料,但是可以選擇用建立一個ContentProvider來管理,也可以直接使用檔案或資料庫,如下面的例子:

package com.android.effective;import android.app.Activity;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.os.Bundle;import android.util.Log;public class SQLiteDatabaseDemo extends Activity {    private static final String TAG = "SQLiteDatabaseDemo";    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        MyDatabase db = new MyDatabase(this);                int id = db.setName("Michael Jordan");        Log.e(TAG, "id of " + id + " is " + db.getName(id));    }        private class MyDatabase {        private static final String name = "demo.db";        private static final String table = "demo";        private final String[] projection = new String[] {"_id", "name" };        private MyDatabaseHelper helper;                public MyDatabase(Context context) {            helper = new MyDatabaseHelper(context, name, null, 1);        }                public String getName(int id) {            final Cursor c = helper.getReadableDatabase().query("demo", projection, "_id=" + id,                    null, null, null, null);            if (c == null || !c.moveToFirst()) {                return null;            }            return c.getString(1);        }                public int setName(String name) {            ContentValues cv = new ContentValues();            cv.put("name", name);            return (int) helper.getWritableDatabase().insert(table, "name", cv);        }    }        private class MyDatabaseHelper extends SQLiteOpenHelper {        public MyDatabaseHelper(Context context, String name,                CursorFactory factory, int version) {            super(context, name, factory, version);        }        @Override        public void onCreate(SQLiteDatabase db) {            db.execSQL("CREATE TABLE demo (_id INTEGER PRIMARY KEY, name TEXT);");        }        @Override        public void onUpgrade(SQLiteDatabase db, int old, int newver) {                    }    }}

這個例子中就沒有使用ContentProvider而是讓Activity直接操作SQLiteDatabase來實現資料的管理,或者不用資料庫而直接使用檔案進行管理資料。
這種方式實現起來可能更簡單,對於需求不大,資料量不大,且只有單一組件使用的情況下,完全可以用這種方式。但是它的缺點也很明顯,就是在組件之間傳遞會十分麻煩,甚至不能夠在組件之間共用。為了共用,就要把資料層進行抽象,使其獨立於任何一個Activity,以滿足不同的組件對資料進行讀寫,但是這樣一來跟實現一個ContentProvider就沒有區別了,還不如實現一個ContentProvider來的方便。
所以,規則就是如果某些資料只在一個Activity中使用,那麼沒有必要建立ContentProvider,直接使用檔案或直接操作Database就可以達到目的。但是如果需要跟其他的組件進行共用和傳遞資料,就必須使用ContentProvider。

另外,有了ContentProvider也可以方便跟其他應用進行互動,把資料傳遞給其他應用的組件。

======================Update on 2012/5/8================================

在使用SQLiteOpenHelper一定要注意線程同步問題,保證每一個SQLiteDatabase的方法(如execSQL)的執行緒安全性,否則可能會引起十分罕見的異常。曾遇到一個SQLiteStatement報出的NPE(NullPointerException),就是由於有多個線程在操作同一個SQLiteOpenHelper,而且沒有同步。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.