内容提供者应用暴露的数据,是被多个其他应用访问(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. 前端学习---JavaScript

    JavaScript基本知识 JavaScript是一门独立的语言,像我们学习php,python等需要安装apache,python3.6,那我们学习JavaScript只需要我们电脑有一个浏览器即 ...

  2. Python 小知识点(9)--反射

    通过字符串映射或修改程序运行时的状态.属性.方法.有如下四个方法 1.hasattr(obj,name_str) , 判断一个对象obj里是否有对应的name_str字符串的方法 2.getattr( ...

  3. IOS Background 之 Background Fetch

    http://www.ithao123.cn/content-1363653.html 定期更新数据的app,比如及时通信类,微博等app. 定期后台获取,等打开后获取的快一些. 30分钟后打开手,获 ...

  4. 太白老师 day06 编码 encode decode

    ASCII : 字母, 数字, 特殊字符 字符:1个字节 数字: 1个字节 Unicode: 万国码, 包含所有文字 创建之初 字符: 2个字节 中文: 2个字节 升级: 字符: 4个字节 中文 : ...

  5. 【310】◀▶ Python 日期和时间

    参考: python 时间日期计算 Python 日期和时间(菜鸟教程) 8.1. datetime — Basic date and time types python中datetime模块中dat ...

  6. Gouraud Shading

    [Gouraud Shading] Gouraud Shading (高洛德着色/高氏着色) 这种着色的效果要好得多,也是在游戏中使用最广泛的一种着色方式.它可对3D模型各顶点的颜色进行平滑.融合处理 ...

  7. Nginx通过CORS实现跨域

    Nginx通过CORS实现跨域 2016-09-01 10:33 阅读 9.4k 评论 0 社区广播:运维派(Yunweipai.com)是国内最早成立的IT运维社区,欢迎大家投稿,让运维人不再孤寂的 ...

  8. Struts2常量详解

    -----------------siwuxie095 Struts2 常量详解 Struts2 的常量大多在默认的配置文件中已经配置好,但根据 用户需求和开发要求的不同,可能需要修改这些常量值,修改 ...

  9. Java核心技术-Java的基本程序设计结构

    1.一个简单的Java应用程序 public class FirstSample { public static void main(String[] args) { System.out.pring ...

  10. C#创建COM组件

    本文详细阐述如何用C#创建COM组件,并能用VC6.0等调用. 附:本文适用任何VS系列工具. 在用C#创建COM组件时,一定要记住以下几点: 1.所要导出的类必须为公有: 2.所有属性.方法也必须为 ...