1. 程式人生 > >Android複習之旅--ContentProvider

Android複習之旅--ContentProvider

資料庫檔案一般是私有的,別的應用程式是沒辦法訪問私有的資料庫。而有些應用的需求是需要把自己私有的資料暴露給別的應用程式訪問,因此就需要用到ContentProvider了

例如系統應用簡訊、聯絡人等都需要暴露自己的資料給其他第三方應用訪問。

原理是該應用通過ContentProvider來暴露資料供其它應用訪問,然後其他應用使用ContentResolver通過Uri來對該應用的資料庫進行操作。

ContentProvider中的主要方法,其子類必須實現

boolean onCreate()  --> 初始化資料
String getType(Uri uri)  --> 根據Uri返回相應的MIME型別(一般預設返回null即可)
Uri insert(Uri uri, ContentValues values)  --> 根據Uri插入一條資料
int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)  --> 根據Uri更新一條資料
int delete(Uri uri, String selection, String[] selectionArgs)  --> 根據Uri刪除一條資料
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)  --> 根據Uri查詢資料並返回Cursor

now,就以一個demo來介紹如何通過ContentResolver來訪問ContentProvider暴露出來的資料吧。

要暴露資料的應用(ContentProvider)

首先,假定應用的資料庫已經建立好了,也寫入了一些記錄。

第一步:建立一個ClientProvider類並繼承ContentProvider,複寫父類的方法,並完成初始化

PersonDBOpenHelper helper;
@Override
public boolean onCreate() {
    helper = new PersonDBOpenHelper(getContext());
        return true;
}

@Override
public String getType(Uri uri) {
    return null;
}

第二步:新增一個Uri匹配器,並設定匹配規則

/**
 * 建立一個uri的匹配器(UriMatcher)
 * 如果路徑匹配不成功就返回 -1
 */
private static UriMatcher um = new UriMatcher(-1);
static{
    /** 
     * 新增一個uri的匹配規則
     * authorities:和清單檔案裡面的要一致
     * path:用於區分uri,可以寫多個,以“/”分隔;例如有多張表時可以【<表名>/query】
     * code:用於確認此uri
     */
    um.addURI("cn.rixin.sqlite.rixindb", "query", 1);//content://cn.rixin.sqlite.rixindb/query 查詢
    um.addURI("cn.rixin.sqlite.rixindb", "insert", 2);//content://cn.rixin.sqlite.rixindb/insert 新增
    um.addURI("cn.rixin.sqlite.rixindb", "delete", 3);//content://cn.rixin.sqlite.rixindb/delete 刪除
    um.addURI("cn.rixin.sqlite.rixindb", "update", 4);//content://cn.rixin.sqlite.rixindb/update 更新
}

第三步:對資料庫進行增刪改查操作

新增記錄

@Override
public Uri insert(Uri uri, ContentValues values) {
    //uri使用者操作的路徑。 檢查uri是否合法。
    int result = um.match(uri);
    if(result == 2){   // 對應Uri中的code
        SQLiteDatabase db = helper.getWritableDatabase();
        long id = db.insert("info", null, values);
        db.close();  // 用完記得要關閉資料庫
        return ContentUris.withAppendedId(uri, id);  // 新增一個id進Uri中並返回
    }else{
        throw new RuntimeException("uri路徑錯誤,不告訴你資料!!!");
    }
}

刪除記錄

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    //uri使用者操作的路徑。 檢查uri是否合法。
    int result = um.match(uri);
    if(result == 3){  // 對應Uri中的code
        SQLiteDatabase db = helper.getWritableDatabase();
        int i = db.delete("info", selection, selectionArgs);
        db.close();  // 用完記得要關閉資料庫
        return i;  //返回受影響的行數
    }else{
        throw new RuntimeException("uri路徑錯誤,不告訴你資料!!!");
    }
}

更改記錄

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    //uri使用者操作的路徑。 檢查uri是否合法。
    int result = um.match(uri);
    if(result == 4){  // 對應Uri中的code
        SQLiteDatabase db = helper.getWritableDatabase();
        int i = db.update("info", values, selection, selectionArgs);
        db.close(); // 用完記得要關閉資料庫
        return i;  //返回受影響的行數
    }else{
        throw new RuntimeException("uri路徑錯誤,不告訴你資料!!!");
    }
}

查詢記錄

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    //uri使用者操作的路徑。 檢查uri是否合法。
    int result = um.match(uri);
    if(result == 1){  // 對應Uri中的code
        //查詢資料,返回資料
        SQLiteDatabase db = helper.getReadableDatabase();
        Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
        db.close();  // 用完記得要關閉資料庫
        return cursor;  // 返回查詢得到的結果集
    }else{
        throw new RuntimeException("uri路徑錯誤,不告訴你資料!!!");
    }
}

最後一步:也是最最容易忘記的一步,在清單檔案中的application裡面配置內容提供者和許可權

配置完整類路徑,主機名(一般寫為【+資料庫名】),還有一定要設定exported屬性為true;然後設定讀寫許可權

<permission android:name="cn.rixin.sqlite.READ" ></permission>
<permission android:name="cn.rixin.sqlite.WRITE"></permission>

<application>
    <provider
        android:name="cn.rixin.sqlite.ClientProvider"
        android:authorities="cn.rixin.sqlite.rixindb"
        android:readPermission="cn.rixin.sqlite.READ"
        android:writePermission="cn.rixin.sqlite.WRITE"
        android:exported="true">
    </provider>
</application>

其他應用(ContentResolver)

第一步:獲取內容提供者的解析器

ContentResolver resolver = getContentResolver();

第二步:進行資料的增刪改查操作

新增記錄

/**
 * 測試新增
 */
public void testInsert(View view){
    //利用內容提供者獲取資料庫db應用的資料
    resolver = getContentResolver();
    //利用解析器通過ClientProvider獲取資料
    Uri uri = Uri.parse("content://cn.rixin.sqlite.rixindb/insert");
    ContentValues values = new ContentValues();
    values.put("username", "Linda");
    values.put("password", "123456");
    Uri uriResult = resolver.insert(uri, values);
    if(uriResult != null){
        Toast.makeText(this, "新增SQLite應用中的資料成功", Toast.LENGTH_SHORT).show();
    }else{
        Toast.makeText(this, "新增SQLite應用中的資料失敗", Toast.LENGTH_SHORT).show();
    }
}

刪除記錄

/**
 * 測試刪除
 */
public void testDelete(View view){ 
    //利用內容提供者獲取資料庫db應用的資料
    resolver = getContentResolver();
    //利用解析器通過ClientProvider獲取資料
    Uri uri = Uri.parse("content://cn.rixin.sqlite.rixindb/delete");
    int i = resolver.delete(uri, "username=?", new String[]{"Linda"});
    if(i > 0){
        Toast.makeText(this, "刪除SQLite應用中的資料成功", Toast.LENGTH_SHORT).show();
    }else{
        Toast.makeText(this, "刪除SQLite應用中的資料失敗", Toast.LENGTH_SHORT).show();
    }
}

更改記錄

/**
 * 測試更新
 */
public void testUpdate(View view){
    //利用內容提供者獲取資料庫db應用的資料
    resolver = getContentResolver();
    //利用解析器通過ClientProvider獲取資料
    Uri uri = Uri.parse("content://cn.rixin.sqlite.rixindb/update");
    ContentValues values = new ContentValues();
    values.put("password", "1008611");
    int i = resolver.update(uri, values, "username=?", new String[]{"Linda"});
    if(i > 0){
        Toast.makeText(this, "更新SQLite應用中的資料成功", Toast.LENGTH_SHORT).show();
    }else{
        Toast.makeText(this, "更新SQLite應用中的資料失敗", Toast.LENGTH_SHORT).show();
    }
}

查詢記錄

/**
 * 測試查詢
 */
public void testQuery(View view){
    //利用內容提供者獲取資料庫db應用的資料
    resolver = getContentResolver();
    //利用解析器通過ClientProvider獲取資料
    Uri uri = Uri.parse("content://cn.rixin.sqlite.rixindb/query");
    Cursor cursor = resolver.query(uri, null, null, null, null);
    while(cursor.moveToNext()){
        int id = cursor.getInt(cursor.getColumnIndex("_id"));
        String username = cursor.getString(cursor.getColumnIndex("username"));
        String password = cursor.getString(cursor.getColumnIndex("password"));
        Toast.makeText(this, id+"---"+username+"---"+password, 0).show();
    }
    cursor.close();
}

第三步:也是最最容易忘記的一步,配置許可權

<uses-permission android:name="cn.rixin.sqlite.READ"/>
<uses-permission android:name="cn.rixin.sqlite.WRITE"/>

至此,demo解釋完畢
如若看不懂,可以看我在上傳在Github上的demo原始碼
SQLite
other

至於獲取簡訊,聯絡人等系統應用中的資料的方法,這裡就不說了,大家可以google搜尋學習哈…

希望以上對您有所幫助。歡迎指(吐)(嘈)