《第一行代碼》學(xué)習(xí)筆記 第 7 章

第 7 章 跨程序共享數(shù)據(jù),探究內(nèi)容提供器

一:ContentResolver 的基本用法

  • 如果想要訪問內(nèi)容提供器中共享的數(shù)據(jù)掺喻,就一定要借助ContentResolve類笨使,可以通過Context中的getContentResolver()方法獲取到該類的實(shí)例
  • 內(nèi)容 URI最標(biāo)準(zhǔn)的格式寫法如下:
content://com.example.app.provider/table1   (這就表示調(diào)用方期望訪問的是 com.example.app 這個(gè)應(yīng)用的 table1 表中的數(shù)據(jù)棠笑。)
content://com.example.app.provider/table1/1 (這就表示調(diào)用方期望訪問的是 com.example.app 這個(gè)應(yīng)用的 table1表中 id 為 1 的數(shù)據(jù)容劳。)
  • 我們可以使用通配符的方式來分別匹配這兩種格式的內(nèi)容 URI,規(guī)則如下
    1. *:表示匹配任意長度的任意字符
    2. '#:表示匹配任意長度的數(shù)字
content://com.example.app.provider/*    (所以必孤,一個(gè)能夠匹配任意表的內(nèi)容 URI格式就可以寫成:)
content://com.example.app.provider/table1/#      (而一個(gè)能夠匹配 table1表中任意一行數(shù)據(jù)的內(nèi)容 URI格式就可以寫成:)
  • 查詢數(shù)據(jù)
    1. 調(diào)用 Uri.parse()方法猾骡,就可以將內(nèi)容 URI字符串解析成 Uri 對(duì)象了
    Uri uri = Uri.parse("content://com.example.app.provider/table1")
2. 現(xiàn)在我們就可以使用這個(gè) Uri對(duì)象來查詢 table1 表中的數(shù)據(jù)了,(查詢完成后返回的仍然是一個(gè) Cursor 對(duì)象)
Cursor cursor = getContentResolver().query(
    uri,
    projection,
    selection,
    selectionArgs,
    sortOrder);
2. 這時(shí)我們就可以將數(shù)據(jù)從 Cursor 對(duì)象中逐個(gè)讀取出來了(遍歷 Cursor 的所有行)
if (cursor != null) {
    while (cursor.moveToNext()) {
       String column1 = cursor.getString(cursor.getColumnIndex("column1"));
       int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
    }
    cursor.close();
}
  • 添加數(shù)據(jù)
    1. 仍然是將待添加的數(shù)據(jù)組裝到 ContentValues 中敷搪,
    2. 然后調(diào)用 ContentResolver的 insert()方法兴想,將 Uri 和 ContentValues作為參數(shù)傳入即可。
    ContentValues values = new ContentValues();
    values.put("column1", "text");
    values.put("column2", 1);
    
    getContentResolver().insert(uri, values);
  • 更新數(shù)據(jù)
    1. 仍然是將待添加的數(shù)據(jù)組裝到 ContentValues 中赡勘,
    2. 然后調(diào)用 ContentResolver的 insert()方法嫂便,將 Uri 和 ContentValues作為參數(shù)傳入即可。
    ContentValues values = new ContentValues();
    values.put("column1", "");
    getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[] {"text", "1"});
  • 刪除數(shù)據(jù)(調(diào)用 ContentResolver 的 delete()方法將這條數(shù)據(jù)刪除掉)
    getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

二:讀取聯(lián)系人 (使用listview顯示)

1. 添加權(quán)限
<uses-permission android:name="android.permission.READ_CONTACTS" />
2. ContactsContract.CommonDataKinds.Phone類已經(jīng)幫我們做好了封裝闸与,提供了一個(gè)CONTENT_URI常量毙替,而這個(gè)常量就是使用Uri.parse()方法解析出來的結(jié)果
    Cursor cursor = null;
    try {
        // 查詢聯(lián)系人數(shù)據(jù)
        cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
        while (cursor.moveToNext()) {
            // 獲取聯(lián)系人姓名
            String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            // 獲取聯(lián)系人手機(jī)號(hào)
            String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            
            contactsList.add(displayName + "\\n" + number);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }

三:創(chuàng)建自己的內(nèi)容提供器

  • 創(chuàng)建內(nèi)容提供器
public class MyProvider extends ContentProvider {
    public static final int TABLE1_DIR = 0;
    public static final int TABLE1_ITEM = 1;
    public static final int TABLE2_DIR = 2;
    public static final int TABLE2_ITEM = 3;
    private static UriMatcher uriMatcher;
    
    static {
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
    uriMatcher.addURI("com.example.app.provider ", "table1/#", TABLE1_ITEM);
    uriMatcher.addURI("com.example.app.provider ", "table2", TABLE2_ITEM);
    uriMatcher.addURI("com.example.app.provider ", "table2/#", TABLE2_ITEM);
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        switch (uriMatcher.match(uri)) {    //借助UriMatcher這個(gè)類就可以輕松地實(shí)現(xiàn)匹配內(nèi)容URI的功能
            case TABLE1_DIR:
            //  查詢table1 表中的所有數(shù)據(jù)
            break;
            case TABLE1_ITEM:
            //  查詢table1 表中的單條數(shù)據(jù)
            break;
            case TABLE2_DIR:
            //  查詢table2 表中的所有數(shù)據(jù)
            break;
            case TABLE2_ITEM:
            //  查詢table2 表中的單條數(shù)據(jù)
            break;
            default:    break;
        }
    }
    
    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case TABLE1_DIR:
                 return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
            case TABLE1_ITEM:
                 return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
            case TABLE2_DIR:
                 return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
            case TABLE2_ITEM:
                 return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
            default:    break;
        }
    return null;
    }
}
  • 實(shí)現(xiàn)跨程序數(shù)據(jù)共享 /跨程序訪問時(shí)我們不能直接使用Toast/
    1. 首先在類的一開始,同樣是定義了四個(gè)常量践樱,分別用于表示訪問Book表中的所有數(shù)據(jù)厂画、訪問Book表中的單條數(shù)據(jù)、訪問Category表中的所有數(shù)據(jù)和訪問Category表中的單條數(shù)據(jù)拷邢。
    2. 然后在靜態(tài)代碼塊里對(duì) UriMatcher進(jìn)行了初始化操作袱院,將期望匹配的幾種 URI格式添加了進(jìn)去。
    3. 接下來就是每個(gè)抽象方法的具體實(shí)現(xiàn)了,
      • query()方法坑填,在這個(gè)方法中先獲取到了SQLiteDatabase的實(shí)例抛人,然后根據(jù)傳入的Uri參數(shù)判斷出用戶想要訪問哪張表,再調(diào)用SQLiteDatabase 的 query()進(jìn)行查詢脐瑰,并將 Cursor 對(duì)象返回就好了。
      • 再往后就是 insert()方法廷臼, 同樣它也是先獲取到了 SQLiteDatabase的實(shí)例苍在,然后根據(jù)傳入的Uri參數(shù)判斷出用戶想要往哪張表里添加數(shù)據(jù), 再調(diào)用 SQLiteDatabase 的 insert()方法進(jìn)行添加就可以了荠商。
      • 接下來就是 update()方法了寂恬,也是先獲取SQLiteDatabase的實(shí)例,然后根據(jù)傳入的Uri參數(shù)判斷出用戶想要更新哪張表里的數(shù)據(jù)莱没,再調(diào)用SQLiteDatabase的 update()方法進(jìn)行更新就好了初肉,受影響的行數(shù)將作為返回值返回。
      • 下面是 delete()方法饰躲,這里仍然是先獲取到 SQLiteDatabase 的實(shí)例牙咏,然后根據(jù)傳入的Uri參數(shù)判斷出用戶想要?jiǎng)h除哪張表里的數(shù)據(jù),再調(diào)用 SQLiteDatabase 的 delete()方法進(jìn)行刪除就好了嘹裂,被刪除的行數(shù)將作為返回值返回妄壶。
      • 最后是 getType()方法,這個(gè)方法中的代碼完全是按照上一節(jié)中介紹的格式規(guī)則編寫的寄狼,相信已經(jīng)沒有什么解釋的必要了丁寄。
    4. 在 AndroidManifest.xml文件中注冊內(nèi)容提供器
<provider
    android:name="com.example.databasetest.DatabaseProvider"
    android:authorities="com.example.databasetest.provider" >
</provider>
public class DatabaseProvider extends ContentProvider {
    public static final int BOOK_DIR = 0;
    public static final int BOOK_ITEM = 1;
    public static final int CATEGORY_DIR = 2;
    public static final int CATEGORY_ITEM = 3;
    public static final String AUTHORITY = "com.example.databasetest.provider";
    private static UriMatcher uriMatcher;
    private MyDatabaseHelper dbHelper;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
        uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
        uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
        uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
    }

    @Override
    public boolean onCreate() {
        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null,
                    sortOrder);
            break;
        case CATEGORY_DIR:
            cursor = db.query("Category", projection, selection, selectionArgs, null, null,
                    sortOrder);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null,
                    null, sortOrder);
            break;
        default:
            break;
        }
        return cursor;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Uri uriReturn = null;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
        case BOOK_ITEM:
            long newBookId = db.insert("Book", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
            break;
        case CATEGORY_DIR:
        case CATEGORY_ITEM:
            long newCategoryId = db.insert("Category", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
            break;
        default:
            break;
        }
        return uriReturn;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updatedRows = 0;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            updatedRows = db.update("Book", values, selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
            break;
        case CATEGORY_DIR:
            updatedRows = db.update("Category", values, selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId });
            break;
        default:
            break;
        }
        return updatedRows;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int deletedRows = 0;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            deletedRows = db.delete("Book", selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
            break;
        case CATEGORY_DIR:
            deletedRows = db.delete("Category", selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            deletedRows = db.delete("Category", "id = ?", new String[] { categoryId });
            break;
        default:
            break;
        }
        return deletedRows;
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book";
        case BOOK_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book";
        case CATEGORY_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category";
        case CATEGORY_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category";
        }
        return null;
    }

}

  • 實(shí)例
    1. 添加數(shù)據(jù)
    Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
    ContentValues values = new ContentValues();
    values.put("name", "A Clash of Kings");
    values.put("author", "George Martin");
    values.put("pages", 1040);
    values.put("price", 22.85);
    Uri newUri = getContentResolver().insert(uri, values);
    newId = newUri.getPathSegments().get(1);
    
    1. 查詢數(shù)據(jù)
    Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
    if (cursor != null) {
        while (cursor.moveToNext()) {
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String author = cursor.getString(cursor.getColumnIndex("author"));
            int pages = cursor.getInt(cursor.getColumnIndex("pages"));
            double price = cursor.getDouble(cursor.getColumnIndex("price"));
            Log.d("MainActivity", "book name is " + name);
            Log.d("MainActivity", "book author is " + author);
            Log.d("MainActivity", "book pages is " + pages);
            Log.d("MainActivity", "book price is " + price);
            }
        cursor.close();
    }
    
    1. 更新數(shù)據(jù)
    Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
    ContentValues values = new ContentValues();
    values.put("name", "A Storm of Swords");
    values.put("pages", 1216);
    values.put("price", 24.05);
    getContentResolver().update(uri, values, null, null);
    
    1. 刪除數(shù)據(jù)
    Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
    getContentResolver().delete(uri, null, null);
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泊愧,隨后出現(xiàn)的幾起案子伊磺,更是在濱河造成了極大的恐慌,老刑警劉巖删咱,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屑埋,死亡現(xiàn)場離奇詭異,居然都是意外死亡腋腮,警方通過查閱死者的電腦和手機(jī)雀彼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來即寡,“玉大人徊哑,你說我怎么就攤上這事〈细唬” “怎么了莺丑?”我有些...
    開封第一講書人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我梢莽,道長萧豆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任昏名,我火速辦了婚禮涮雷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘轻局。我一直安慰自己洪鸭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開白布仑扑。 她就那樣靜靜地躺著览爵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪镇饮。 梳的紋絲不亂的頭發(fā)上蜓竹,一...
    開封第一講書人閱讀 50,043評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音储藐,去河邊找鬼俱济。 笑死,一個(gè)胖子當(dāng)著我的面吹牛邑茄,可吹牛的內(nèi)容都是我干的姨蝴。 我是一名探鬼主播,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼肺缕,長吁一口氣:“原來是場噩夢啊……” “哼左医!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起同木,我...
    開封第一講書人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤浮梢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后彤路,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秕硝,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年洲尊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了远豺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坞嘀,死狀恐怖躯护,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丽涩,我是刑警寧澤棺滞,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布裁蚁,位于F島的核電站赌厅,受9級(jí)特大地震影響庵寞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蟆盐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一移必、第九天 我趴在偏房一處隱蔽的房頂上張望室谚。 院中可真熱鬧,春花似錦避凝、人聲如沸舞萄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撑螺,卻和暖如春含思,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甘晤。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來泰國打工含潘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人线婚。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓遏弱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親塞弊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漱逸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 一、簡介 Content Provider用法有兩種: 1游沿、使用現(xiàn)有的CP來讀取和操作相應(yīng)程序中的數(shù)據(jù)饰抒;比如系統(tǒng)電...
    在你左右2018閱讀 683評(píng)論 0 2
  • 文件存儲(chǔ),SharedPreferences存儲(chǔ)以及數(shù)據(jù)庫存儲(chǔ)诀黍,使用這些持久化技術(shù)所保存的數(shù)據(jù)都只能在當(dāng)前應(yīng)用程序...
    努力生活的西魚閱讀 570評(píng)論 0 0
  • 內(nèi)容提供器 思維導(dǎo)圖 最近在練習(xí)使用思維導(dǎo)圖袋坑,獻(xiàn)一下丑。眯勾。枣宫。 什么是內(nèi)容提供器 內(nèi)容提供器主要用于在不同應(yīng)用程序間...
    HeilHelloWorld閱讀 789評(píng)論 2 4
  • 參考: 內(nèi)容提供程序基礎(chǔ)知識(shí) 創(chuàng)建內(nèi)容提供程序 一. 用途: 跨程序共享數(shù)據(jù)(為其他應(yīng)用程序提供訪問數(shù)據(jù)的接口) ...
    NickelFox閱讀 1,105評(píng)論 2 13
  • 讓夢想中的世界通過我們的轉(zhuǎn)變得以實(shí)現(xiàn)。我相信吃环,除非從我做起也颤,我們的夢想就不可能實(shí)現(xiàn)。不幸的是模叙,我們總是希望別人先開...
    G小君閱讀 624評(píng)論 0 0