1. 程式人生 > >Android-Observer(內容觀察者)

Android-Observer(內容觀察者)

內容提供者應用暴露的資料,是被多個其他應用訪問(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理解為:廣播, 只是程式碼和廣播不一樣而已