Android 淺析 ContentProvider (一) 使用
前言
Linus Benedict Torvalds : RTFSC – Read The Fucking Source Code
概括
Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don't need to share data amongst multiple applications you can use a database directly via SQLiteDatabase.
我們先來(lái)看一張圖片讓我們對(duì)Content Provider有一個(gè)直觀(guān)的了解:
ContentProvider提供了在應(yīng)用程序之前共享數(shù)據(jù)的一種機(jī)制。
1、存儲(chǔ)和獲取數(shù)據(jù)提供了統(tǒng)一的接口至耻。
2破加、對(duì)數(shù)據(jù)進(jìn)行封裝剧防,不用關(guān)心數(shù)據(jù)存儲(chǔ)的細(xì)節(jié)旦装。
3笛坦、Android為常見(jiàn)的一些數(shù)據(jù)提供了默認(rèn)的ContentProvider(包括音頻狠持、視頻疟位、圖片和通訊錄等)。
最主要的是ContentProvider對(duì)外共享數(shù)據(jù)統(tǒng)一了數(shù)據(jù)的訪(fǎng)問(wèn)方式喘垂。
組件使用
首先來(lái)看下如何實(shí)現(xiàn)一個(gè)ContentProvider功能:
功能簡(jiǎn)述
服務(wù)端:
有六個(gè)最主要的方法需要重寫(xiě):
1甜刻、onCreate() which is called to initialize the provider.
2、query(Uri, String[], String, String[], String) which returns data to the caller.
3正勒、insert(Uri, ContentValues) which inserts new data into the content provider.
4罢吃、update(Uri, ContentValues, String, String[]) which updates existing data in the content provider.
5、delete(Uri, String, String[]) which deletes data from the content provider.
6昭齐、getType(Uri) which returns the MIME type of data in the content provider.
注意:
insert()和update()方法有可能被多線(xiàn)程調(diào)用尿招,一定要是線(xiàn)程安全的。
onCreate()方法只會(huì)調(diào)用一次阱驾,但要避免冗長(zhǎng)的操作就谜。
客戶(hù)端:
通過(guò)ContentResolver可以自動(dòng)獲取Provider的實(shí)例,不必?fù)?dān)心跨進(jìn)程調(diào)用的細(xì)節(jié)里覆。
代碼例子
服務(wù)端:
AndroidManifest.xml
<!-- android:exported="true" 指示該服務(wù)是否能夠被其他應(yīng)用程序組件調(diào)用或跟它交互丧荐。 -->
<provider
android:name="com.unknow.jason.testdatabaseex.DatabaseProvider"
android:authorities="com.unknow.jason.testdatabaseex.provider"
android:exported="true"
android:enabled="true" >
</provider>
淺析:
AndroidManifest添加provider服務(wù),在安裝App的時(shí)候會(huì)自動(dòng)注冊(cè)這個(gè)Provider服務(wù)到AMS里作備份喧枷,這個(gè)服務(wù)最關(guān)鍵的點(diǎn)是authorities虹统,作為Provider唯一標(biāo)識(shí),讓其它程序可以在A(yíng)MS里面查詢(xún)到此Provider服務(wù)隧甚。
ps.更多關(guān)于Provider的權(quán)限可以看http://developer.android.com/guide/topics/manifest/provider-element.html车荔。
DatabaseProvider.java
public class DatabaseProvider extends ContentProvider {
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
}
淺析:
Provider最主要的六個(gè)方法。
getType():
Implement this to handle requests for the MIME type of the data at the given URI. The returned MIME type should start with vnd.android.cursor.item for a single record, or vnd.android.cursor.dir/ for multiple items.
注意: 這方法有可能用于多線(xiàn)程戚扳。用于訪(fǎng)問(wèn)此信息的應(yīng)用程序不需要權(quán)限忧便;如果您的內(nèi)容提供者需要讀和/或?qū)憴?quán)限,或不導(dǎo)出帽借,所有應(yīng)用程序都可以調(diào)用此方法珠增,不管其訪(fǎng)問(wèn)權(quán)限超歌。這使他們能夠檢索URI的MIME類(lèi)型時(shí),調(diào)度意圖蒂教。
insert():
Implement this to handle requests to insert a new row. As a courtesy, call notifyChange() after inserting.
注意: 這方法有可能用于多線(xiàn)程巍举。
onCreate():
Implement this to initialize your content provider on startup. This method is called for all registered content providers on the application main thread at application launch time. It must not perform lengthy operations, or application startup will be delayed.
注意: 如果你使用SQLite進(jìn)行數(shù)據(jù)庫(kù)操作,切勿在此方法中調(diào)用getReadableDatabase() or getWritableDatabase()方法凝垛,作為代替禀综,可以使用onOpen(SQLiteDatabase)作為第一次初始數(shù)據(jù)庫(kù)。
query():
Implement this to handle query requests from clients.
注意: 這方法有可能用于多線(xiàn)程苔严。
delete():
Implement this to handle requests to delete one or more rows. The implementation should apply the selection clause when performing deletion, allowing the operation to affect multiple rows in a directory. As a courtesy, call notifyChange() after deleting.
注意: 這方法有可能用于多線(xiàn)程。如果一個(gè)特定的行要被刪除孤澎,它會(huì)在URI的末尾解析出這一行的ID届氢。
update():
Implement this to handle requests to update one or more rows. The implementation should update all rows matching the selection to set the columns according to the provided values map. As a courtesy, call notifyChange() after updating.
注意: 這方法有可能用于多線(xiàn)程。
sqlhelper.java
public class SqlHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
public static final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement, "
+ "category_name text)";
public SqlHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
onCreate(db);
}
}
客戶(hù)端:
Uri uri = Uri.parse("content://com.unknow.jason.testdatabaseex.provider/book");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
}
}
淺析:
getContentResolver().query():
Query the given URI, returning a Cursor over the result set with optional support for cancellation.
為了更佳的性能覆旭,調(diào)用者應(yīng)該遵循兩點(diǎn):
1退子、提供一個(gè)明確的projection,防止從存儲(chǔ)中讀取不需要的數(shù)據(jù)型将。
2寂祥、使用問(wèn)號(hào)參數(shù)標(biāo)記,如“電話(huà)=七兜?”而不是在選擇參數(shù)中的顯式值丸凭,因此,不同的值的查詢(xún)將被確認(rèn)為緩存的目的相同的腕铸。