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

Android-Observer(内容观察者)的更多相关文章

  1. Android中内容观察者的使用---- ContentObserver类详解 (转)

    前言: 工作中,需要开启一个线程大量的查询某个数据库值发送了变化,导致的开销很大,后来在老大的指点下,利用了 ContentObserver完美的解决了该问题,感到很兴奋,做完之后自己也对Conten ...

  2. Android 利用内容观察者实现短信窃听

    <Android 内容观察者的原理>中介绍了内容观察者的一些基本原理,并做了简单的实战,本文接着进一步做一个小项目实战 package com.wuyudong.smslistener; ...

  3. 无废话Android之内容观察者ContentObserver、获取和保存系统的联系人信息、网络图片查看器、网络html查看器、使用异步框架Android-Async-Http(4)

    1.内容观察者ContentObserver 如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider 发生数据变化时调 ...

  4. android ContentObserver内容观察者基本使用

    package com.example.observertest; import android.content.ContentResolver; import android.database.Co ...

  5. Android -- ContentObserver 内容观察者

    1. 实现原理图 2. 示例代码 (暂时有个问题,短信观察者 收到一条短信时 onchange方法会执行两次, 解决方法为:每次监听到变化的时候就去取最新短信的id,跟上次取的比较,如果一样的就不做处 ...

  6. Android中内容观察者的使用---- ContentObserver类详解

    详解:http://blog.csdn.net/qinjuning/article/details/7047607

  7. Android 内容观察者的原理

    拦截短信,比如当发短信的时候,就把短信读取出来,当系统的短信发生变化的时候,大叫一声,把数据发送到公共的消息邮箱里面,我们的应用通过内容观察者观察公共的消息邮箱 获取ContentResolver对象 ...

  8. Android开发之内容观察者

    内容观察者: 当关注应用的数据库数据改变时,内容提供者会发出通知,在内容提供者的uri上注册一个内容观察者,就可以收到数据改变的通知 实现步骤: 1.假如是自定义的ContentProvider,需要 ...

  9. Android(java)学习笔记253:ContentProvider使用之内容观察者02

    下面通过3个应用程序之间的交互说明一下内容观察者: 一. 如下3个应用程序为相互交互的: 二.交互逻辑图: 三.具体代码: 1.   16_数据库工程: (1)数据库帮助类BankDBOpenHelp ...

随机推荐

  1. Mysql进行复杂查询

    1.查询“生物”课程比“物理”课程成绩高的所有学生的学号: 思路: (1)获取所有选了 生物 课程的学生的成绩(学号,成绩) --临时表     (2)获取所有选了 物理 课程的学生的成绩(学号,成绩 ...

  2. preprocess

    1,宏定义,有参宏,无参宏,宏定义实现的是定义一个符号常量; 条件编译3种方式,文件包含含义; 不带参数的宏定义;既用一个指定的的标识符来代替一个字符串; #define RUIY 10000000 ...

  3. 实现ls -l

    就是遍历一个目录下面的所有文件,显示信息 Linux下面有点绕 要通过 opendir打开目录,返回一个DIR结构 用readdir来读DIR结构,返回目录下面的第一项,是个dirent结构体,再次调 ...

  4. sysbench基准测试工具使用

    1.源码编译安装 源码下载地址(目前有0.4/0.5/1.0三个分支版本):https://github.com/akopytov/sysbench 编译安装: unzip sysbench-1.0. ...

  5. react之本地图片引用

    react之本地图片引用 <img src="../images/photo.png"/> 这种写法在react中是不支持的,所以引用本地图片需要用import或者re ...

  6. Android MVP模式简单易懂的介绍方式 (二)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...

  7. addClass()使用方法

    含义:为元素添加指定的样式名 具体用法分为以下两种: 1.可以一次添加一个或者多个用空格隔开的样式名 例: <script> $("ul li").addClass(& ...

  8. Unsupported compiler 'com.apple.compilers.llvmgcc42' selected for architecture 'armv7' Xcode5

    刚刚将Xcode更新到Xcode5,一运行报如下错误: Unsupported compiler 'com.apple.compilers.llvmgcc42' selected for archit ...

  9. Django创建一个简单的blog

    1. 使用django-admin.py 创建mysite项目 sunny@sunny-ThinkPad-T450:~/PycharmProjects$ django-admin.py startpr ...

  10. 搭建Git Server - 个人开发简单搭建

    ###################### 教程一 ####################### 1. 创建git用户和用户组 #新建一个git用户组 sudo groupadd git #新建一 ...