Android基礎(chǔ)-ContentProvider

ContentProvider是Android的四大組件的成員,它能為數(shù)據(jù)提供外部訪問接口啤月,即其他應(yīng)用也能訪問到該應(yīng)用的數(shù)據(jù)品腹,類似于共享的數(shù)據(jù)庫苦银。

ContentProvider

常見用法

  1. 通過其他應(yīng)用的ContentProvider訪問其應(yīng)用數(shù)據(jù)
  2. 創(chuàng)建本地的ContentProvider為其他應(yīng)用提供數(shù)據(jù)訪問服務(wù)

訪問聯(lián)系人的數(shù)據(jù)

首先添加幾個聯(lián)系人姻灶,我國著名詩人-->李白杜甫

聯(lián)系人
讀取聯(lián)系人數(shù)據(jù)

由于Android6.0以上讀取聯(lián)系人需要申請權(quán)限,所以我們先在Manifest中添加好權(quán)限

    <uses-permission android:name="android.permission.READ_CONTACTS" />

然后還需要在Activity中進行權(quán)限的申請

這里要注意Manifest中的權(quán)限要和Activity中的權(quán)限一致

由于我之前在Activity中申請的權(quán)限是Manifest.permission_group.CONTACTS
然后進入應(yīng)用的時候老是彈出no permission的Toast
兩個地方的權(quán)限不一致的話诈茧,系統(tǒng)會默認(rèn)拒絕該權(quán)限的申請产喉,然后我為此折騰了半天...

        //檢查是否有讀取聯(lián)系人的權(quán)限
        int hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
        if (hasPermission == PackageManager.PERMISSION_DENIED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE_CONTRACTS);
        } else {
            //這里進行讀取聯(lián)系人的數(shù)據(jù)
            read();
        }
    //-----------------------------------分界線------------------------------------//
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_CODE_CONTRACTS) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                read();
            } else {
                Toast.makeText(this, "no permission", Toast.LENGTH_SHORT).show();
            }
        }
    }

讀取聯(lián)系人給的外部數(shù)據(jù)接口需要用到ContentReslover類

  1. 通過Context.getContentReslover獲取ContentReslover
  2. 調(diào)用ContentReslover的查詢方法query
  3. 通過Cursor一步一步的把數(shù)據(jù)傳入ArrayList中
private void read() {
        Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                //這就是ListView的數(shù)據(jù)源-->contacts
                contacts.add(name + ": " + number);

            }
            cursor.close();
        }
    }

然后通過ListView展示出讀取的數(shù)據(jù)


image.png

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

其實ContentProvider的操作跟SQLiteDatabase差不多的
新建一個繼承自ContentProvider的類-->StudentProvider,實現(xiàn)如下方法:

  1. onCreate:
  2. insert
  3. delete
  4. update
  5. query
  6. getType
    • getType方法是獲取Uri對象對應(yīng)的MIME類型(類似于ID吧)
    • contentProvider中的任意表對應(yīng)就是"vnd.android.cursor"+"dir"+"/vnd."+authorities+表名
    • 表中任意的數(shù)據(jù)對應(yīng)"vnd.android.cursor"+"item"+"/vnd."+authorities+表名
    • 也就一個地方不同敢会,dir和item的區(qū)別
        <provider
            android:name=".lesson6.StudentProvider"
            android:authorities="org.fourstars.firstcode.provider"
            android:enabled="true"
            android:exported="true">

        </provider>

注意清單文件中的authorities要和Activity中的AUTHORITY一致
因為ContentProvider是通過Uri來訪問數(shù)據(jù)的曾沈,我們使用UriMatcher來匹配到合適的uri

URI的標(biāo)準(zhǔn)寫法

content://+authorities+表名
在authorities后加入"/*",如 content://ort.fourstars.firstcode.provider/ * 就能匹配到任意表
在authorities后加入"表名/#"鸥昏,就能匹配到表中的任意數(shù)據(jù)

public class StudentProvider extends ContentProvider {
    public static final int STUDENT_DIR = 1111;
    public static final int STUDENT_ITEM = 1110;
    public static final String AUTHORITY = "ort.fourstars.firstcode.provider";

    private static UriMatcher uriMatcher;

    private DbHelper dbHelper;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);
        uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);
    }

    public StudentProvider() {
    }

    @Override
    public boolean onCreate() {
        dbHelper = new DbHelper(getContext());
        // TODO: Implement this to initialize your content provider on startup.
        return true;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();

        return db.delete("Student", "number = ?", new String[]{uri.getPathSegments().get(1)});
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case STUDENT_DIR:
                return "vnd.android.cursor.dir/vnd." + AUTHORITY + ".student";
            case STUDENT_ITEM:
                return "vnd.android.cursor.item/vnd." + AUTHORITY + ".student";
            default:
                break;
        }
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();

        Long number = db.insert("Student", null, values);
        Log.d("tag", "insert: " + number);
        return Uri.parse("content://" + AUTHORITY + "/student/" + number);
    }


    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = dbHelper.getReadableDatabase();

        return db.query("Student", projection, selection, selectionArgs, null, null, sortOrder);
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();

        return db.update("Student", values, "name = ?", new String[]{uri.getPathSegments().get(1)});

    }
}

這里沿用數(shù)據(jù)存儲篇中的工程來展示效果塞俱,onClick中代碼更改如下

            //搜索結(jié)果這里
            case R.id.btn_search:
                printTable();
                setBlank();
                break;
    //-----------------------------------分界線------------------------------------//

 private void printTable() {
        StringBuilder stringBuilder = new StringBuilder();
//        Cursor cursor = db.query("Student", null, null, null, null, null, null, null);
        Uri uri = Uri.parse(contentUri);
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        
        if (cursor.moveToFirst()) {
            do {
                String n = cursor.getString(cursor.getColumnIndex("name"));
                String b = cursor.getString(cursor.getColumnIndex("number"));

                stringBuilder.append("姓名:" + n + ",學(xué)號:" + b + "\n");
            } while (cursor.moveToNext());
        }
        tvStudent.setText("學(xué)生數(shù)據(jù):\n" + stringBuilder.toString());
        cursor.close();
    }

寫入
寫入三個數(shù)據(jù)吏垮,結(jié)果如圖所示

image.png

            case R.id.btn_insert:
                ContentValues cv = getContentValues();
                //                db.insert("Student", null, cv);
                Uri uri = Uri.parse(contentUri);
                getContentResolver().insert(uri, cv);
                //清空Editext的輸入
                setBlank();
                break;

刪除
通過學(xué)號刪除xima這個學(xué)生

image.png


            case R.id.btn_delete:
                String number = etNumber.getText().toString();
                if (!number.isEmpty()){
                    //                    db.delete("Student", "number = ?", new String[]{number});
                    Uri uriDelete = Uri.parse(contentUri + "/" + number);
                    getContentResolver().delete(uriDelete, null, null);
                    setBlank();
                }

                break;

更新
libai的學(xué)號更新到233

image.png
            case R.id.btn_update:
                String name = etName.getText().toString();
                Uri uriUpdate = Uri.parse(contentUri + "/" + name);
                if (!name.isEmpty())
                    getContentResolver().update(uriUpdate, getContentValues(), null, null);
//                    db.update("Student", getContentValues(), "name = ?", new String[]{name});

                setBlank();
                break;

最后

我覺得吧ContentProvider就跟數(shù)據(jù)庫差不多障涯,就調(diào)用的方式有所差別罐旗。
然后由于我在數(shù)據(jù)存儲篇偷懶只弄了一張表,這邊也只能是一張表唯蝶,因為跟書上的有所區(qū)別九秀,改了我好久,好慘啊...
偷懶需謹(jǐn)慎啊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粘我,一起剝皮案震驚了整個濱河市鼓蜒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌征字,老刑警劉巖都弹,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匙姜,居然都是意外死亡畅厢,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門搁料,熙熙樓的掌柜王于貴愁眉苦臉地迎上來或详,“玉大人,你說我怎么就攤上這事郭计“郧伲” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵昭伸,是天一觀的道長梧乘。 經(jīng)常有香客問我,道長庐杨,這世上最難降的妖魔是什么选调? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮灵份,結(jié)果婚禮上仁堪,老公的妹妹穿的比我還像新娘。我一直安慰自己填渠,他們只是感情好弦聂,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氛什,像睡著了一般莺葫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枪眉,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天捺檬,我揣著相機與錄音,去河邊找鬼贸铜。 笑死堡纬,一個胖子當(dāng)著我的面吹牛聂受,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播隐轩,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼饺饭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了职车?” 一聲冷哼從身側(cè)響起瘫俊,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悴灵,沒想到半個月后扛芽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡积瞒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年川尖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茫孔。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡叮喳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缰贝,到底是詐尸還是另有隱情馍悟,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布剩晴,位于F島的核電站锣咒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赞弥。R本人自食惡果不足惜毅整,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绽左。 院中可真熱鬧悼嫉,春花似錦、人聲如沸拼窥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闯团。三九已至,卻和暖如春仙粱,著一層夾襖步出監(jiān)牢的瞬間房交,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工伐割, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留候味,地道東北人刃唤。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像白群,于是被迫代替她去往敵國和親尚胞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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