内容提供者应用暴露的数据,是被多个其他应用访问(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理解为:广播, 只是代码和广播不一样而已