日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

cursoradpter自动更新

發(fā)布時(shí)間:2024/4/17 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cursoradpter自动更新 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


03 November 2014
Android Cursor自動(dòng)更新的實(shí)現(xiàn)和原理


在Android日常開發(fā)中,時(shí)常會(huì)請(qǐng)求數(shù)據(jù)到Cursor,然后再通過Cursor獲取數(shù)據(jù)。像SQLiteDatabase和ContentProvider都使用了Cursor。在這些應(yīng)用中,往往希望當(dāng)數(shù)據(jù)發(fā)生改變時(shí),Cursor也會(huì)自動(dòng)的更新數(shù)據(jù)。這篇文章,我就會(huì)向你闡述如何通過Android自身的API實(shí)現(xiàn)Cursor的自動(dòng)更新。另外我還將向你闡述這背后的原理。通過這些原理你可以舉一反三的實(shí)現(xiàn)更為廣泛的自動(dòng)跟新。


文章中的代碼


可以在https://github.com/KOHOH1992/CursorSyncDemo中找到文章中出現(xiàn)的代碼


該項(xiàng)目共有4個(gè)分支。use_provider分支介紹了使用ContentProvider實(shí)現(xiàn)Cursor同步更新的方法。use_database分支介紹了不使用ContentProvider實(shí)現(xiàn)Cursor同步更新的方法。use_adapter分支介紹了不使用Loader實(shí)現(xiàn)Cursor同步更新的方法。


Cursor自動(dòng)更新的實(shí)現(xiàn)


前提


首先假設(shè)項(xiàng)目使用了如下的前提


數(shù)據(jù)存儲(chǔ)在SqliteDataBase當(dāng)中
通對(duì)ContentProvider的請(qǐng)求,獲取封裝了數(shù)據(jù)的Cursor
使用CursorLoader加載數(shù)據(jù)
使用AdapterView和CursorAdapter顯示數(shù)據(jù)
定義同步標(biāo)志


static final Uri SYNC_SIGNAL_URI = Uri.parse(
? ? "content://com.kohoh.cursorsyncdemo/SYNC_SIGNAL");
在ContentProvider的query中設(shè)置NotificationUri


@Override
public Cursor query(Uri uri, String[] projection, String selection, String[]?
selectionArgs,String sortOrder) {
? ? SQLiteDatabase database = sqLiteOpenHelper.getReadableDatabase();
? ? Cursor cursor = database.query(ContactContract.CONTACT_TABLE, projection,
? ? selection,selectionArgs, null, null, sortOrder);
? ? //設(shè)置NotificationUri
? ? cursor.setNotificationUri(contentResolver, ContactContract.SYNC_SIGNAL_URI);
? ? return cursor;
}
在ContentProvider的insert,update,delete中觸發(fā)NotificationUri


@Override
public Uri insert(Uri uri, ContentValues values) {
? ? SQLiteDatabase database = sqLiteOpenHelper.getWritableDatabase();
? ? long id = database.insert(ContactContract.CONTACT_TABLE, null, values);


? ? if (id >= 0) {
? ? ? ? //觸發(fā)NotificationUri
? ? ? ? contentResolver.notifyChange(ContactContract.SYNC_SIGNAL_URI, null);
? ? }


? ? return uri.withAppendedPath(ContactContract.CONTACT_URI, String.valueOf(id));
}
@Override
public int update(Uri uri, ContentValues values, String selection,?
? ? String[] selectionArgs) {
? ? SQLiteDatabase database = sqLiteOpenHelper.getWritableDatabase();
? ? int result = database.update(ContactContract.CONTACT_TABLE, values,?
? ? ? ? selection, selectionArgs);


? ? if (result > 0) {
? ? ? ? //觸發(fā)NotificationUri
? ? ? ? contentResolver.notifyChange(ContactContract.SYNC_SIGNAL_URI, null);
? ? }


? ? return result;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
? ? SQLiteDatabase database = sqLiteOpenHelper.getWritableDatabase();
? ? int result = database.delete(ContactContract.CONTACT_TABLE, selection,?
? ? ? ? selectionArgs);


? ? if (result > 0) {
? ? //觸發(fā)NotificationUri
? ? contentResolver.notifyChange(ContactContract.SYNC_SIGNAL_URI, null);
? ? }


? ? return result;
}
Cursor的實(shí)現(xiàn)原理


Android的Cursor自動(dòng)更新是通過觀察者模式實(shí)現(xiàn)的,整個(gè)過程如下圖所示






通過ContentPorvider和ContentResolver使得數(shù)據(jù)發(fā)生了改變
ContentProvider通知Cursor的觀察者數(shù)據(jù)發(fā)生了改變
Cursor通知CursorLoader的觀察者數(shù)據(jù)發(fā)生了改變
CursorLoader通過ContentProvider加載新的數(shù)據(jù)
ContentPovider向DataBase請(qǐng)求新的數(shù)據(jù)
CursorLoader調(diào)用CursorAdapter#changeCursor,用封裝了新數(shù)據(jù)的Cursor替換舊的Cursor
CursorAdapter告知AdapterView的觀察者有新的數(shù)據(jù)
AdapterView重新加載并顯示數(shù)據(jù)
在Android的android.database包下,有一個(gè)ContentObserver。Android正是通過他來實(shí)現(xiàn)觀察者模式的。當(dāng)數(shù)據(jù)改變之后,觀察者會(huì)將數(shù)據(jù)改變的消息通知相應(yīng)的對(duì)象,進(jìn)而做出反饋。在代碼中,當(dāng)數(shù)據(jù)改變之后,我會(huì)調(diào)用ContentResolver#notifyChange,發(fā)出ContactContract.SYNC_SIGNAL_URI信號(hào),通知數(shù)據(jù)發(fā)生了改變。而在此之前,從ContentProvider#query中獲得的Cursor已經(jīng)通過Cursor#setNotificationUri對(duì)ContactContract.SYNC_SIGNAL_URI信號(hào)進(jìn)行了監(jiān)視。當(dāng)該信號(hào)出現(xiàn),Cursor就會(huì)將信息改變的消息告訴CursorLoader的觀察者(在此之前CursorLoader已經(jīng)對(duì)該Cursor設(shè)立了觀察者)。CursorLoader會(huì)開始重新開始加載數(shù)據(jù)。當(dāng)數(shù)據(jù)加載成功,CursorLoader會(huì)通過CursorAdapter#changeCursor設(shè)置封裝了新數(shù)據(jù)的Cursor。而后CursorAdapter又會(huì)通知AdapterView的觀察者數(shù)據(jù)發(fā)生了改變(在此之前AdapterView已經(jīng)對(duì)CursorAdapter設(shè)立了觀察者)。最后AdapterView就會(huì)重新加載并顯示新的數(shù)據(jù)。






在整個(gè)過程當(dāng)中,我要做的就是在改變數(shù)據(jù)時(shí)發(fā)出信號(hào),對(duì)封裝數(shù)據(jù)的Cursor設(shè)置需要監(jiān)視的信號(hào)。具體的說就是在query中調(diào)用Cursor#setNotificationUri,在insert、update、delete中調(diào)用ContentResolver#notifyChange。這里需要補(bǔ)充的是Cursor和ContentResolver的信號(hào)機(jī)制同樣是通過觀察者模式實(shí)現(xiàn)的。


其他的實(shí)現(xiàn)方式


這里要介紹的其他的實(shí)現(xiàn)方式,依舊是通過觀察者模式實(shí)現(xiàn)的。區(qū)別在于是否使用ContentProvider和CursorLoader


不使用ContentProvider


在開發(fā)過程中,如果數(shù)據(jù)不用于應(yīng)用之間的共享,使用ContentProvider似乎有一些多余。然而Android提供的CursorLoader的API必須通過ContentProvider才能實(shí)現(xiàn)數(shù)據(jù)加載和數(shù)據(jù)同步更新。但是你任然可以在不使用ContentProvider的情況下實(shí)現(xiàn)Cursor的自動(dòng)更新。你需要做的只是在你的Loader中加入下面的代碼


// 實(shí)例化一個(gè)全局的ForceLoadContentObserver?
ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
@Override
public Cursor loadInBackground() {
? ? SQLiteDatabase database = mSqLiteOpenHelper.getReadableDatabase();
? ? Cursor cursor = database.query(mTable, mColumns, mSelection, mSelectionArgs,?
? ? ? ? mGroupBy,mHaving, mOrderBy);
? ? if (cursor != null) {
? ? ? ? cursor.getCount();
? ? ? ? // 對(duì)Cursor設(shè)立觀察者
? ? ? ? cursor.registerContentObserver(mObserver);
? ? ? ? // 設(shè)置Cursor的觀察信號(hào)
? ? ? ? cursor.setNotificationUri(getContext().getContentResolver(),?
? ? ? ? ? ? mNotificationUri);
? ? }
? ? return cursor;
}
ForceLoadContentObserver是Loader的內(nèi)部類。當(dāng)觀察到數(shù)據(jù)發(fā)生變化之后,該類會(huì)調(diào)用Loader#forceLoad,進(jìn)而開始重新加載數(shù)據(jù)。另外你也可以直接使用我項(xiàng)目中的DatabaseLoader。該類是我參照CursorLoader編寫的一個(gè)工具,通過它你可以繞過ContentProvider,直接請(qǐng)求Database。


不使用Loader


如果你不想要使用Loader(我非常不贊成你這么做),你可以通過如下的代碼實(shí)現(xiàn)Cursor的同步更新。


// 使用CursorAdapter.FLAG_AUTO_REQUERY標(biāo)志
adapter = new SimpleCursorAdapter(this, R.layout.contact_item, null, from, to,
? ? ? ? CursorAdapter.FLAG_AUTO_REQUERY);
private void loadData() {
? ? SQLiteOpenHelper sqliteOpenHelper = ContactContract.getSqliteOpenHelper(this);
? ? SQLiteDatabase database = sqliteOpenHelper.getReadableDatabase();
? ? String[] columns = {ContactContract._ID, ContactContract.NAME,?
? ? ? ? ContactContract.PHONE};
? ? Cursor cursor = database.query(ContactContract.CONTACT_TABLE, columns, null,?
? ? ? ? null, null,null, null);
? ? //設(shè)置NotificationUri
? ? cursor.setNotificationUri(this.getContentResolver(),?
? ? ? ? ContactContract.SYNC_SIGNAL_URI);
? ? adapter.changeCursor(cursor);
}
這里的關(guān)鍵在于,在實(shí)例化CursorAdapter時(shí)使用了CursorAdapter.FLAGAUTOREQUERY標(biāo)志。當(dāng)使用該標(biāo)志后,每當(dāng)收到數(shù)據(jù)更新的消息,CursorAdapter就會(huì)自己調(diào)用CursorAdapter#requery重新加載數(shù)據(jù)。然而整個(gè)加載過程會(huì)再UI線程中發(fā)生,這很有可能會(huì)使得程序運(yùn)行部流暢。正是因?yàn)檫@個(gè)原因該方法以及被Android設(shè)置為Deprecated了。因此如果有可能,我還是推薦你使用Loader。


就是這樣!!

總結(jié)

以上是生活随笔為你收集整理的cursoradpter自动更新的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。