使用ContentProvider跨進程共享數(shù)據(jù)

歡迎Follow我的GitHub, 關注我的簡書. 其余參考Android目錄.

Logo

本文的合集已經編著成書读规,高級Android開發(fā)強化實戰(zhàn)驳规,歡迎各位讀友的建議和指導硫惕。在京東即可購買:https://item.jd.com/12385680.html

Android

ContentProvider主要應用于進程間數(shù)據(jù)共享. 對于應用而言, 多進程并不會經常使用, 因而較少使用ContentProvider, 是最不常見的四大組件(Activity, Service, BroadcastReceiver, ContentProvider). 但是其優(yōu)異的性能與便捷, 對于多應用共享數(shù)據(jù)而言, 非常重要, 比如共享同一份計步數(shù)據(jù)等. 開發(fā)者只有掌握多種技能, 才能在開發(fā)中游刃有余, 用最優(yōu)的方式完成項目, 提升應用性能, 間接提高用戶體驗. 本文借用Demo, 講解ContentProvider共享數(shù)據(jù)的要點.

本文源碼的GitHub下載地址


SQLite

ContentProvider需要媒介進行數(shù)據(jù)存儲, 最常用的就是SQLite數(shù)據(jù)庫.

SQLite數(shù)據(jù)庫繼承SQLiteOpenHelper類, 提供數(shù)據(jù)庫名稱, 表名, 版本. 在onCreate方法中, 創(chuàng)建數(shù)據(jù)庫表, 添加字段.

本示例使用兩張表, 書籍和用戶.

public class DbOpenHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "book_provider.db";
    public static final String BOOK_TABLE_NAME = "book";
    public static final String USER_TABLE_NAME = "user";

    private static final int DB_VERSION = 1;

    private String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS "
            + BOOK_TABLE_NAME + "(_id INTEGER PRIMARY KEY, name TEXT)";

    private String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS "
            + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY, name TEXT, sex INT)";

    public DbOpenHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK_TABLE);
        db.execSQL(CREATE_USER_TABLE);
    }

    @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

直接使用數(shù)據(jù)庫的情況較少, 也比較復雜, 推薦使用一些經典ORM數(shù)據(jù)庫, 如Sugar等, 簡化管理. ORM, 即對象關系映射.


ContentProvider

ContentProvider提供數(shù)據(jù)訪問的接口, CRUD增刪改查. 在onCreate中, 初始化數(shù)據(jù)庫, 并添加數(shù)據(jù).

@Override public boolean onCreate() {
    showLogs("onCreate 當前線程: " + Thread.currentThread().getName());
    mContext = getContext();

    initProviderData(); // 初始化Provider數(shù)據(jù)

    return false;
}

private void initProviderData() {
    mDb = new DbOpenHelper(mContext).getWritableDatabase();
    mDb.execSQL("delete from " + DbOpenHelper.BOOK_TABLE_NAME);
    mDb.execSQL("delete from " + DbOpenHelper.USER_TABLE_NAME);
    mDb.execSQL("insert into book values(3,'Android');");
    mDb.execSQL("insert into book values(4, 'iOS');");
    mDb.execSQL("insert into book values(5, 'HTML5');");
    mDb.execSQL("insert into user values(1, 'Spike', 1);");
    mDb.execSQL("insert into user values(2, 'Wang', 0);");
}

CRUD的參數(shù)是Uri, 數(shù)據(jù)庫需要使用表名, 為了便于從Uri映射到表名, 使用關系轉換.

private String getTableName(Uri uri) {
    String tableName = null;
    switch (sUriMatcher.match(uri)) {
        case BOOK_URI_CODE:
            tableName = DbOpenHelper.BOOK_TABLE_NAME;
            break;
        case USER_URI_CODE:
            tableName = DbOpenHelper.USER_TABLE_NAME;
            break;
        default:
            break;
    }
    return tableName;
}

添加數(shù)據(jù)insert, 可以注冊內容改變的監(jiān)聽, 插入數(shù)據(jù)時, 廣播更新, 即notifyChange.

@Nullable @Override public Uri insert(Uri uri, ContentValues values) {
    showLogs("insert");
    String table = getTableName(uri);
    if (TextUtils.isEmpty(table)) {
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
    mDb.insert(table, null, values);

    // 插入數(shù)據(jù)后通知改變
    mContext.getContentResolver().notifyChange(uri, null);
    return null;
}

刪除數(shù)據(jù)delete, 返回刪除數(shù)據(jù)的數(shù)量, 大于0即刪除成功.

@Override public int delete(Uri uri, String selection, String[] selectionArgs) {
    showLogs("delete");

    String table = getTableName(uri);
    if (TextUtils.isEmpty(table)) {
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
    int count = mDb.delete(table, selection, selectionArgs);
    if (count > 0) {
        mContext.getContentResolver().notifyChange(uri, null);
    }

    return count; // 返回刪除的函數(shù)
}

修改數(shù)據(jù)update, 與刪除類似, 返回修改數(shù)據(jù)的數(shù)量.

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    showLogs("update");

    String table = getTableName(uri);
    if (TextUtils.isEmpty(table)) {
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
    int row = mDb.update(table, values, selection, selectionArgs);
    if (row > 0) {
        mContext.getContentResolver().notifyChange(uri, null);
    }

    return row; // 返回更新的行數(shù)
}

查詢數(shù)據(jù)query, 返回數(shù)據(jù)庫的游標, 處理數(shù)據(jù).

@Nullable @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    showLogs("query 當前線程: " + Thread.currentThread().getName());
    String tableName = getTableName(uri);
    if (TextUtils.isEmpty(tableName)) {
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
    return mDb.query(tableName, projection, selection, selectionArgs, null, null, sortOrder, null);
}

注意Uri和表名的轉換可能為空, 使用TextUtils.isEmpty判空.


共享數(shù)據(jù)

使用ContentProvider的獨立進程, 模擬進程間共享數(shù)據(jù).

<provider
    android:name=".BookProvider"
    android:authorities="org.wangchenlong.book.provider"
    android:permission="org.wangchenlong.BOOK_PROVIDER"
    android:process=":provider"/>

在AndroidManifest中, 把Provider注冊在:provider進程中, 與主進程分離.

添加數(shù)據(jù), 通過Uri找到ContentProvider, 使用ContentResolverinsert方法, 添加ContentValues數(shù)據(jù).

public void addBooks(View view) {
    Uri bookUri = BookProvider.BOOK_CONTENT_URI;
    ContentValues values = new ContentValues();
    values.put("_id", 6);
    values.put("name", "信仰上帝");
    getContentResolver().insert(bookUri, values);
}

查詢數(shù)據(jù)query, 與數(shù)據(jù)庫的使用方式類似, 解析出Cursor, 通過移動Cursor, 找到所有匹配的結果.

public void showBooks(View view) {
    String content = "";
    Uri bookUri = BookProvider.BOOK_CONTENT_URI;
    Cursor bookCursor = getContentResolver().query(bookUri, new String[]{"_id", "name"}, null, null, null);
    if (bookCursor != null) {
        while (bookCursor.moveToNext()) {
            Book book = new Book();
            book.bookId = bookCursor.getInt(0);
            book.bookName = bookCursor.getString(1);
            content += book.toString() + "\n";
            Log.e(TAG, "query book: " + book.toString());
            mTvShowBooks.setText(content);
        }
        bookCursor.close();
    }
}

效果

效果

ContentProvider封裝了跨進程共享的邏輯, 我們只需要Uri即可訪問數(shù)據(jù), 使用共享數(shù)據(jù)非常便捷, 需要掌握簡單的使用方式.

OK, that's all! Enjoy it!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末叁巨,一起剝皮案震驚了整個濱河市财岔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌龟虎,老刑警劉巖璃谨,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鲤妥,居然都是意外死亡佳吞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門旭斥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來容达,“玉大人古涧,你說我怎么就攤上這事垂券。” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵菇爪,是天一觀的道長算芯。 經常有香客問我,道長凳宙,這世上最難降的妖魔是什么熙揍? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮氏涩,結果婚禮上届囚,老公的妹妹穿的比我還像新娘。我一直安慰自己是尖,他們只是感情好意系,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饺汹,像睡著了一般蛔添。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兜辞,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天迎瞧,我揣著相機與錄音,去河邊找鬼逸吵。 笑死凶硅,一個胖子當著我的面吹牛,可吹牛的內容都是我干的扫皱。 我是一名探鬼主播咏尝,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼啸罢!你這毒婦竟也來了编检?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤扰才,失蹤者是張志新(化名)和其女友劉穎允懂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衩匣,經...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蕾总,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了琅捏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片生百。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖柄延,靈堂內的尸體忽然破棺而出蚀浆,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布市俊,位于F島的核電站揍魂,受9級特大地震影響否过,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一虫蝶、第九天 我趴在偏房一處隱蔽的房頂上張望纽什。 院中可真熱鬧合溺,春花似錦凑队、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汉规,卻和暖如春礼殊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背针史。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工晶伦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人啄枕。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓婚陪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親频祝。 傳聞我的和親對象是個殘疾皇子泌参,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容