1.什么是ContentProvider
首先,ContentProvider(內(nèi)容提供者)是android中的四大組件之一,但是在一般的開發(fā)中,可能使用的比較少。
ContentProvider為不同的軟件之間數(shù)據(jù)共享,提供統(tǒng)一的接口。也就是說,如果我們想讓其他的應(yīng)用使用我們自己程序內(nèi)的數(shù)據(jù),就可以使用ContentProvider定義一個對外開放的接口,從而使得其他的應(yīng)用可以使用咱們應(yīng)用的文件、數(shù)據(jù)庫內(nèi)存儲的信息。當然,自己開發(fā)的應(yīng)用需要給其他應(yīng)用共享信息的需求可能比較少見,但是在Android系統(tǒng)中,很多系統(tǒng)自帶應(yīng)用,比如聯(lián)系人信息,圖片庫,音頻庫等應(yīng)用,為了對其他應(yīng)用暴露數(shù)據(jù),所以就使用了ContentProvider機制。所以,我們還是要學(xué)習(xí)ContentProvider的基本使用,在遇到獲取聯(lián)系人信息,圖片庫,音頻庫等需求的時候,才能更好的實現(xiàn)功能
2.如何定義一個ContentProvider
Android系統(tǒng)為了讓我們更好的對外暴露數(shù)據(jù),提供了統(tǒng)一的接口,所以定義了抽象類ContentProvider,因此,如果我們想對外提供數(shù)據(jù),我們需要繼承ContentProvider,并且實現(xiàn)下面的這幾個方法:
onCreate()
當我們的provider初始化時被調(diào)用,我們應(yīng)該在這個方法里面完成部分初始化操作
query() 查詢方法,用于給調(diào)用者返回數(shù)據(jù)
insert() 插入操作,用于讓外部應(yīng)用插入數(shù)據(jù)到內(nèi)容提供者中
update() 更新操作,用于更新內(nèi)容提供者的數(shù)據(jù)
delete() 用于刪除數(shù)據(jù)
getType 返回內(nèi)容提供者的MIME Type
上面這些方法,當我們繼承自ContentProvider的時候,eclipse會自動的給我們添加,但是這并不代表我們每個方法都需要自定義實現(xiàn)。如果我們只希望給其他應(yīng)用提供數(shù)據(jù),而不允許其他應(yīng)用修改我們的數(shù)據(jù),那么我們只需要實現(xiàn)onCreate(),getType()和query()這三個方法就可以了,其他的三個方法我們可以根據(jù)業(yè)務(wù)需求,實現(xiàn)或者是不實現(xiàn)。
因為一般使用ContentProvider向外部暴露數(shù)據(jù)庫的信息,因此,本篇將以使用ContentProvider向其他應(yīng)用暴露數(shù)據(jù)庫信息為例,講解ContentProvider的基本使用。
Android中SQLite數(shù)據(jù)庫的創(chuàng)建和使用,本篇不再介紹,不清楚的請看這篇文章
假設(shè)讀者已經(jīng)學(xué)會了SQLite數(shù)據(jù)庫的使用,并且已經(jīng)建立好了數(shù)據(jù)庫,下面我們開始寫我們的ContentProvider。
因為注釋解析的比較詳細,所以就不過多解釋了
public class StudentProvider extends ContentProvider { // 數(shù)據(jù)庫操作類,用于獲取SQLiteDatabase private static final int STUDENT = 1; private static final int STUDENTS = 2; // UriMatcher類是一個很重要的類,因為我們需要根據(jù)傳入的uri,來判斷執(zhí)行相對應(yīng)的操作 private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH); // 靜態(tài)代碼塊用于初始化MATCHER需要匹配的uri // MATCHER.addURI(主機名(用于唯一標示一個ContentProvider,這個需要和清單文件中的authorities屬性相同),路徑(可以用來表示我們要操作的數(shù)據(jù),路徑的構(gòu)建應(yīng)根據(jù)業(yè)務(wù)而定),返回值(用于匹配uri的時候,作為匹配的返回值)); MATCHER.addURI("com.example.mydbdemo.StudentProvider", "student", STUDENTS); MATCHER.addURI("com.example.mydbdemo.StudentProvider", "student/#", STUDENT); public boolean onCreate() { dbHelper = new MyDbOpenHelper(getContext()); // 如果uri為 content://com.example.mydbdemo.StudentProvider/student // 則代表查詢所有的student表內(nèi)的數(shù)據(jù) // 如果uri為 content://com.example.mydbdemo.StudentProvider/student/6 // 則代表查詢student表內(nèi)id=6的數(shù)據(jù) public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbHelper.getReadableDatabase(); //判斷傳入的uri到底匹配哪一個,從而實現(xiàn)不同的業(yè)務(wù)需求 switch (MATCHER.match(uri)) { //db.query(表明, 要查詢的列(是一個String數(shù)組), where條件, where條件中的參數(shù), groupBy, having, sortOrder); return db.query("student", projection, selection, selectionArgs, null, null, sortOrder); //查詢某一個id對應(yīng)的學(xué)生的信息 long id = ContentUris.parseId(uri); String where = "id=" + id; //將selection查詢信息拼接到我們的where條件中 if (selection != null && !"".equals(selection)) { where = selection + " and " + where; return db.query("student", projection, where, selectionArgs, null, null, sortOrder); //如uri不匹配,拋出不合法參數(shù)的異常 throw new IllegalArgumentException("Unkwon Uri:" + uri.toString()); public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = dbHelper.getWritableDatabase(); switch (MATCHER.match(uri)) { long id = db.insert("student", "name", values); return ContentUris.withAppendedId(uri, id); throw new IllegalArgumentException("Uri不匹配"); public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); switch (MATCHER.match(uri)) { count = db.delete("student", selection, selectionArgs); long id = ContentUris.parseId(uri); String where = "id=" + id; if (selection != null && !"".equals(selection)) { where = selection + " and " + where; count = db.delete("student", where, selectionArgs); throw new IllegalArgumentException("Unkwon Uri:" + uri.toString()); public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); switch (MATCHER.match(uri)) { count = db.update("student", values, selection, selectionArgs); long id = ContentUris.parseId(uri); String where = "id=" + id; if (selection != null && !"".equals(selection)) { where = selection + " and " + where; count = db.update("student", values, where, selectionArgs); throw new IllegalArgumentException("Unkwon Uri:" + uri.toString()); public String getType(Uri uri) { switch (MATCHER.match(uri)) { return "vnd.android.cursor.item/student"; return "vnd.android.cursor.dir/student"; throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
我們在定義好我們的ContentProvider之后,因為 ContentProvider數(shù)據(jù)四大組件之一,因此我們還需要在AndroidManifest清單文件中進行注冊才能使用,下面是注冊信息
<!-- 不要忘記exported這個屬性,如果不加,可能會導(dǎo)致外部程序訪問失敗,錯誤信息為權(quán)限拒絕 --> <!-- authorities這個屬性就是我們在ContentProvider中使用的addURI方法時的第一個參數(shù)的取值 --> android:name="com.example.mydbdemo.StudentProvider" android:authorities="com.example.mydbdemo.StudentProvider" >
注意,provider的聲明和activity一樣,都是在application節(jié)點進行聲明的。
至此,我們就完成了我們自己的ContentProvider的生命,其他的應(yīng)用現(xiàn)在就可以使用我們往外部暴露的數(shù)據(jù)信息了。
3.外部應(yīng)用如何使用我們的ContentProvider
我們已經(jīng)定義好了我們自己的ContentProvider,那么外部應(yīng)用如何調(diào)用呢?
下面,我將新建一個測試單元工程,完成對ContentProvider的各個方法的測試
添加方法測試
//使用ContentProvider添加數(shù)據(jù)的測試 public void testadd() throws Throwable { //獲取ContentResolver對象,完成對ContentProvider的調(diào)用 ContentResolver contentResolver = this.getContext().getContentResolver(); Uri insertUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student"); ContentValues values = new ContentValues(); values.put("name", "zhaokaikai"); values.put("school", "bbbb"); //返回值為我們剛插入進入的數(shù)據(jù)的uri地址 Uri uri = contentResolver.insert(insertUri, values); Log.i(TAG, uri.toString());
刪除方法測試
//使用ContentProvider刪除數(shù)據(jù)的測試 public void testDelete() throws Throwable { ContentResolver contentResolver = this.getContext().getContentResolver(); Uri deleteUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6"); contentResolver.delete(deleteUri, null, null);
修改方法測試
//使用ContentProvider更新數(shù)據(jù)的測試 public void testUpdate() throws Throwable { ContentResolver contentResolver = this.getContext().getContentResolver(); Uri updateUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6"); ContentValues values = new ContentValues(); values.put("name", "testUp"); values.put("age", "101"); values.put("school", "ccccc"); contentResolver.update(updateUri, values, null, null);
//使用ContentProvider查詢數(shù)據(jù)的測試 public void testFind() throws Throwable { ContentResolver contentResolver = this.getContext().getContentResolver(); //這個uri用于查詢所有的數(shù)據(jù),若查詢某個id的數(shù)據(jù),則構(gòu)建下面的uri //Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/要查詢的id"); Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student"); Cursor cursor = contentResolver.query(selectUri, null, null, null, "id desc"); while (cursor.moveToNext()) { int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); String school = cursor.getString(cursor.getColumnIndex("school")); Log.i(TAG, "id=" + id + ",name=" + name + ",age=" + age +",school="+school);
上面的方法都經(jīng)過了單元測試。
好了,至此,我們就使用ContentProvider實現(xiàn)了在第三方應(yīng)用中對我們應(yīng)用的數(shù)據(jù)庫進行增刪改查等操作
|