Android ContentProvider 使用

1、簡介

ContentProvider 為存儲和獲取數(shù)據(jù)提供統(tǒng)一的接口诊县÷饴ィ可以在不同的應(yīng)用程序之間共享數(shù)據(jù)。Android已經(jīng)為常見的一些數(shù)據(jù)提供了默認(rèn)的 ContentProvider赴肚。

數(shù)據(jù)通過唯一的 URI 標(biāo)識來源素跺。ContentProvider 將數(shù)據(jù)看作表,查詢 / 操作數(shù)據(jù)的時候誉券,通過類似數(shù)據(jù)庫操作的 insert / delete / query / update 方法來實(shí)現(xiàn)增刪查改操作指厌。

作為應(yīng)用間數(shù)據(jù)交換 / 共享接口,當(dāng)然需要有一個“橋梁”來連接數(shù)據(jù)提供方和使用方踊跟。數(shù)據(jù)提供方提供數(shù)據(jù)踩验,使用方使用 content://authorities/path 類似的 URI 來訪問數(shù)據(jù)鸥诽。

2、數(shù)據(jù)提供方

2.1箕憾、Provider 聲明

數(shù)據(jù)提供方需要在 Androidmanifest.xml 中聲明 ContentProvider 組件牡借。一個 ContentProvider 組件聲明如下:

<permission
    android:name="com.straw.providerhost.course.read"
    android:protectionLevel="normal"/>
<permission
    android:name="com.straw.providerhost.course.write"
    android:protectionLevel="normal"/>

<application>
    <provider
        android:authorities="com.straw.course"
        android:name="com.straw.providerhost.CourseContentProvider"
        android:exported="true"
        android:readPermission="com.straw.providerhost.course.read"
        android:writePermission="com.straw.providerhost.course.write"/>
</application>
屬性 含義
authorities 指定 authorieties(類似包名的格式,如 com.xx.xx)袭异,訪問者通過 content://authorities/path 的形式訪問
name 這個 Provider 對應(yīng)的 Java 類名
exported true 則表示導(dǎo)出钠龙。不設(shè)置或設(shè)置為 false 時,其他應(yīng)用如果使用這個 Provider御铃,則會出現(xiàn) java.lang.SecurityException: Permission Denial 錯誤
readPermission 讀數(shù)據(jù)者所需聲明權(quán)限碴里,數(shù)據(jù)訪問者不聲明權(quán)限則會出現(xiàn) java.lang.SecurityException: Permission Denial 錯誤
writePermission 寫數(shù)據(jù)者所需聲明權(quán)限,數(shù)據(jù)訪問者不聲明權(quán)限則會出現(xiàn) java.lang.SecurityException: Permission Denial 錯誤

2.2上真、其他情況

那兩個 App 同時聲明相同 authorities 的 ContentProvider 可不可以呢咬腋?答案是 不行。如果兩個 App 聲明了相同 authorities 的 Provider睡互,第二個 App 在安裝時會出現(xiàn) INSTALL_FAILED_CONFLICTING_PROVIDER 錯誤根竿。錯誤如下:

Provider 沖突

2.3、ContentProvider 類

一個具體的 ContentProvider 類需要繼承自 android.content.ContentProvider湃缎,并且實(shí)現(xiàn) onCreate / getType / insert / delete / update / query 這幾個方法犀填。一般我們在 onCreate 方法中打開數(shù)據(jù)庫蠢壹,在對應(yīng)的操作方法中根據(jù) URI 的不同嗓违,操作不同的數(shù)據(jù)。

先定義一個幫助類图贸,來聲明一些常量蹂季。例如:

public class CourseProviders {

    public static final String AUTHORITIES = "com.straw.course";
    public static final String COURSE_PATH = "course";


    public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITIES);
    public static final Uri COURSE_URI = Uri.withAppendedPath(BASE_URI, COURSE_PATH);


    public static class CourseColumn {

        public static final String ID = "id";
        public static final String NAME = "NAME";
        public static final String TEACHER_NAME = "teacher_name";
        public static final String WATCH_COUNT = "watch_count";
        public static final String VIDEO_URL = "video_url";
    }
}

然后實(shí)現(xiàn)具體的 ContentProvider:

public class CourseContentProvider extends ContentProvider {

    private CourseSqliteHelper mSqliteHelper;
    private SQLiteDatabase mDatabase;
    private UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);


    private static final int PROVIDE_COURSE = 1;


    @Override
    public boolean onCreate() {
        mSqliteHelper = new CourseSqliteHelper(getContext());
        mDatabase = mSqliteHelper.getWritableDatabase();

        mUriMatcher.addURI(CourseProviders.AUTHORITIES,
                CourseProviders.COURSE_PATH, PROVIDE_COURSE);
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection,
            String selection, String[] selectionArgs, String sortOrder) {

        switch (mUriMatcher.match(uri)) {
            case PROVIDE_COURSE:
                return mDatabase.query(CourseSqliteHelper.COURSE_TABLE_NAME,
                        projection, selection, selectionArgs, null, null, sortOrder);

            default:
                break;
        }

        return null;
    }

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

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {
        Uri result = null;
        switch (mUriMatcher.match(uri)) {
            case PROVIDE_COURSE:
                long rowId = mDatabase.insert(
                        CourseSqliteHelper.COURSE_TABLE_NAME, null, values);
                result = ContentUris.withAppendedId(uri, rowId);
                break;

            default:
                break;
        }

        return result;
    }

    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
        switch (mUriMatcher.match(uri)) {
            case PROVIDE_COURSE:
                return mDatabase.delete(CourseSqliteHelper.COURSE_TABLE_NAME,
                        selection, selectionArgs);

            default:
                break;
        }

        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        switch (mUriMatcher.match(uri)) {
            case PROVIDE_COURSE:
                return mDatabase.update(CourseSqliteHelper.COURSE_TABLE_NAME,
                        values, selection, selectionArgs);

            default:
                break;
        }

        return 0;
    }
}

通過 android.content.UriMatcher 提供的 match 方法,很方便的將 content://authorities/path 這樣的訪問 URI 匹配到正確的數(shù)據(jù)訪問路徑疏日。

3偿洁、數(shù)據(jù)訪問方

我們可以在本應(yīng)用內(nèi)通過 ContentProvider 訪問,也可以在其他應(yīng)用中訪問沟优。在 ContentProvider 所在應(yīng)用外訪問時涕滋,會拉起 ContentProvider 所在的 App(會拉起 Application,但不會打開任何 Activity)挠阁。

3.1宾肺、權(quán)限聲明

首先,在使用方的 AndroidManifest.xml 中需要聲明所使用 ContentProvider 的權(quán)限侵俗,如果只讀就聲明讀權(quán)限锨用,如果讀寫都需要就聲明讀寫權(quán)限。如:

<uses-permission android:name="com.straw.providerhost.course.read"/>
<uses-permission android:name="com.straw.providerhost.course.write"/>

3.2隘谣、具體使用

private void queryAll() {
    Cursor cursor = context.getContentResolver().query(CourseProviders.COURSE_URI, null, null, null, null);
    if (cursor == null) {
        return;
    }

    mCourseInfoList.clear();
    while (cursor.moveToNext()) {
        CourseInfo info = new CourseInfo();
        info.mId = cursor.getString(cursor.getColumnIndex(CourseProviders.CourseColumn.ID));
        info.mName = cursor.getString(cursor.getColumnIndex(CourseProviders.CourseColumn.NAME));
        info.mTeacherName = cursor.getString(cursor.getColumnIndex(CourseProviders.CourseColumn.TEACHER_NAME));
        info.mWatchCount = cursor.getInt(cursor.getColumnIndex(CourseProviders.CourseColumn.WATCH_COUNT));
        info.mVideoUrl = cursor.getString(cursor.getColumnIndex(CourseProviders.CourseColumn.VIDEO_URL));

        mCourseInfoList.add(info);
    }

    cursor.close();

    mAdapter.notifyDataSetChanged();
}

通過 context.getContentResolver 方法獲取 ContentResolver增拥,然后使用其提供的 insert / delete / update / query 方法進(jìn)行 增刪改查 操作即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掌栅,隨后出現(xiàn)的幾起案子秩仆,更是在濱河造成了極大的恐慌,老刑警劉巖猾封,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逗概,死亡現(xiàn)場離奇詭異,居然都是意外死亡忘衍,警方通過查閱死者的電腦和手機(jī)逾苫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枚钓,“玉大人铅搓,你說我怎么就攤上這事〔蠼荩” “怎么了星掰?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嫩舟。 經(jīng)常有香客問我氢烘,道長,這世上最難降的妖魔是什么家厌? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任播玖,我火速辦了婚禮,結(jié)果婚禮上饭于,老公的妹妹穿的比我還像新娘蜀踏。我一直安慰自己,他們只是感情好掰吕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布果覆。 她就那樣靜靜地躺著,像睡著了一般殖熟。 火紅的嫁衣襯著肌膚如雪局待。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天菱属,我揣著相機(jī)與錄音钳榨,去河邊找鬼。 笑死照皆,一個胖子當(dāng)著我的面吹牛重绷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膜毁,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼昭卓,長吁一口氣:“原來是場噩夢啊……” “哼愤钾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起候醒,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤能颁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后倒淫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伙菊,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年敌土,在試婚紗的時候發(fā)現(xiàn)自己被綠了镜硕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡返干,死狀恐怖兴枯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矩欠,我是刑警寧澤财剖,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站癌淮,受9級特大地震影響躺坟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乳蓄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一咪橙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧栓袖,春花似錦匣摘、人聲如沸店诗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庞瘸。三九已至捧弃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間擦囊,已是汗流浹背违霞。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞬场,地道東北人买鸽。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像贯被,于是被迫代替她去往敵國和親眼五。 傳聞我的和親對象是個殘疾皇子妆艘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

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

  • 參考Content Providers 對于ContentProvider, 可以把它看做為一個數(shù)據(jù)庫, 數(shù)據(jù)庫中...
    AssIstne閱讀 1,999評論 1 3
  • 這篇主要介紹下ContentProvider如何實(shí)現(xiàn)共享數(shù)據(jù)、及ContentResolver如何訪問其他進(jìn)程等數(shù)...
    朋永閱讀 2,458評論 0 5
  • Android下的進(jìn)程與線程: 1看幼、進(jìn)程的生命周期: 1)批旺、進(jìn)程的創(chuàng)建及回收: 進(jìn)程是被系統(tǒng)創(chuàng)建的,當(dāng)內(nèi)存不足的時...
    重炎閱讀 1,222評論 0 7
  • 不止是秋冬季,夏季肌膚也需要用身體乳護(hù)理棚唆。 這個時候暇赤,如果你不想用冬天油油的身體乳, 不如看看最新發(fā)售的這款宵凌,能讓...
    哆咗閱讀 1,089評論 0 6
  • ? 轉(zhuǎn)眼間今天已經(jīng)是十二月十一日翎卓,距離我參加第一場校園招聘會已經(jīng)快三個月。 兩個月來摆寄,參加了大大小小的各種招聘會...
    佳呦閱讀 254評論 1 1