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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cursoradpter自动更新

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


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


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


文章中的代碼


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


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


Cursor自動更新的實現(xiàn)


前提


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


數(shù)據(jù)存儲在SqliteDataBase當(dāng)中
通對ContentProvider的請求,獲取封裝了數(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的實現(xiàn)原理


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






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






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


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


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


不使用ContentProvider


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


// 實例化一個全局的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();
? ? ? ? // 對Cursor設(shè)立觀察者
? ? ? ? cursor.registerContentObserver(mObserver);
? ? ? ? // 設(shè)置Cursor的觀察信號
? ? ? ? cursor.setNotificationUri(getContext().getContentResolver(),?
? ? ? ? ? ? mNotificationUri);
? ? }
? ? return cursor;
}
ForceLoadContentObserver是Loader的內(nèi)部類。當(dāng)觀察到數(shù)據(jù)發(fā)生變化之后,該類會調(diào)用Loader#forceLoad,進(jìn)而開始重新加載數(shù)據(jù)。另外你也可以直接使用我項目中的DatabaseLoader。該類是我參照CursorLoader編寫的一個工具,通過它你可以繞過ContentProvider,直接請求Database。


不使用Loader


如果你不想要使用Loader(我非常不贊成你這么做),你可以通過如下的代碼實現(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)鍵在于,在實例化CursorAdapter時使用了CursorAdapter.FLAGAUTOREQUERY標(biāo)志。當(dāng)使用該標(biāo)志后,每當(dāng)收到數(shù)據(jù)更新的消息,CursorAdapter就會自己調(diào)用CursorAdapter#requery重新加載數(shù)據(jù)。然而整個加載過程會再UI線程中發(fā)生,這很有可能會使得程序運行部流暢。正是因為這個原因該方法以及被Android設(shè)置為Deprecated了。因此如果有可能,我還是推薦你使用Loader。


就是這樣!!

總結(jié)

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

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