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理解為:廣播, 只是代碼和廣播不一樣而已

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM