Android-Observer(內容觀察者)
阿新 • • 發佈:2018-12-17
內容提供者應用暴露的資料,是被多個其他應用訪問(insert,update,delete,query),但如果L應用要查詢(內容提供者應用暴露的資料),難道要開啟子執行緒一直迴圈去查詢 ?
答:開啟子執行緒一直迴圈去查詢是不合理的(是嚴重的錯誤),所以Android提供了Observer(內容觀察者)這種機制,當內容提供者裡面的資料傳送變化(insert, update, delete),就會發出通知,L應用監聽到發出的通知,就去查詢資料,這樣就完美解決了這個問題。
以下這幅圖:把 (監聽uri資料的變化:內容觀察者ContentObserver)寫到了L應用裡面,其實是L應用呼叫ContentResolver .監聽uri資料的變化:內容觀察者ContentObserver
S應用--> MyContentProvider 增刪改查 程式碼
只有 insert,update, delete,能夠證明資料傳送了改變,所以通過getContext().getContentResolver().notifyChange(uri, null);發出改變通知
private MySqliteOpenHeper mySqliteOpenHeper; /** * 只要在AndroidManifest.xml中配置了provider元件 * 應用開啟後,會自動啟動此方法 *@return */ @Override public boolean onCreate() { Log.d(TAG, "onCreate()"); mySqliteOpenHeper = MySqliteOpenHeper.getInstance(getContext()); return false; } /** * 查詢 * @return */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db= mySqliteOpenHeper.getReadableDatabase(); // 查詢全部 Cursor cursor = db.query("cat", // 表名 projection, // 查詢的列 null, // selection 查詢的條件 xxx=? null, // selectionArgs 查詢條件的值 null, // groupBy 分組 null, // having 分組過濾條件 "_id desc"); // orderBy 排序 --> 倒序 // 在內容提供者裡面,千萬不能關閉資料庫,關閉遊標 return cursor; } /** * 增加 * @return */ @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase database = mySqliteOpenHeper.getWritableDatabase(); long resultID = database.insert("cat", null, values); // 在內容提供者裡面,千萬不能關閉資料庫,關閉遊標 /** * 證明資料傳送了改變,所以需要通知其他應用 * 內容觀察者機制: -->發出改變通知給---> 其他應用(內容觀察者監聽器,監聽到傳送的改變通知,然後進行查詢) */ getContext().getContentResolver().notifyChange(uri, null); return uri; } /** * 修改 * @return */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase database = mySqliteOpenHeper.getWritableDatabase(); // 引數一:表名 引數二:其他應用傳遞過來的ContentValues 引數三:其他應用傳遞過來的查詢條件 int updateResult = database.update("cat", values, selection, selectionArgs); // 在內容提供者裡面,千萬不能關閉資料庫,關閉遊標 /** * 證明資料傳送了改變,所以需要通知其他應用 * 內容觀察者機制: -->發出改變通知給---> 其他應用(內容觀察者監聽器,監聽到傳送的改變通知,然後進行查詢) */ getContext().getContentResolver().notifyChange(uri, null); return updateResult; } /** * 刪除 * @return */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase database = mySqliteOpenHeper.getWritableDatabase(); int deleteResult = database.delete("cat", selection, selectionArgs); // 在內容提供者裡面,千萬不能關閉資料庫,關閉遊標 /** * 證明資料傳送了改變,所以需要通知其他應用 * 內容觀察者機制: -->發出改變通知給---> 其他應用(內容觀察者監聽器,監聽到傳送的改變通知,然後進行查詢) */ getContext().getContentResolver().notifyChange(uri, null); return deleteResult; }
S應用--> AndroidManifest.xml 對外暴露:
<!-- MyContentProviderNew是元件需要配置 可以把MyContentProviderNew看作是伺服器 authorities 看作是伺服器 伺服器有訪問的連結,authorities(授權) ,是唯一標識 android:enabled="true" 可以被系統例項化 android:exported="true" 允許對外輸出 --> <provider android:authorities="autho.prov.cp.MyContentProviderNew" android:name=".cp.MyContentProviderNew" android:enabled="true" android:exported="true" />
L應用 --> NewMainActivity監聽發出的改變通知
package liudeli.cp.client; import android.app.Activity; import android.content.ContentResolver; import android.database.ContentObserver; import android.net.Uri; import android.os.Bundle; import android.os.Handler; public class NewMainActivity extends Activity { /** * 定義ContentResolver */ private ContentResolver contentResolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // S應用對外暴露的授權標識 Uri uri = Uri.parse("content://autho.prov.cp.MyContentProviderNew"); contentResolver = getContentResolver(); /** * 註冊 內容觀察者:監聽S應用發出的改變通知 * 引數一:S應用提供的授權 * 引數二:意思是 是否監 和它表有關係的表 (例如:.../dog .../dog/#) * 引數三:監聽器 * * 註冊監聽: 需要:contentResolver. */ contentResolver.registerContentObserver(uri, true, contentObserver); } /** * 監聽器:用來監聽S應用發出的改變通知 */ private ContentObserver contentObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); /** * 通過contentProvider.query(......) 進行查詢S應用資料 */ } @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); /** * 通過contentProvider.query(......) 進行查詢S應用資料 */ } }; @Override protected void onDestroy() { super.onDestroy(); /** * 解除:內容觀察者:監聽 * 解除也需要:contentResolver. */ contentResolver.unregisterContentObserver(contentObserver); } }
可以把 內容觀察者ContentObserver理解為:廣播, 只是程式碼和廣播不一樣而已