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理解为:广播, 只是代码和广播不一样而已

原文地址:https://www.cnblogs.com/android-deli/p/10129601.html