当前位置: 代码迷 >> Android >> Android中内容观察者的应用- ContentObserver类详解
  详细解决方案

Android中内容观察者的应用- ContentObserver类详解

热度:36   发布时间:2016-05-01 20:29:34.0
Android中内容观察者的使用---- ContentObserver类详解

前言: 工作中,需要开启一个线程大量的查询某个数据库值发送了变化,导致的开销很大,后来在老大的指点下,利用了

???? ContentObserver完美的解决了该问题,感到很兴奋,做完之后自己也对ContentObserver做下总结。

?

????????? ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于

?? 数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器,

? 相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的。

?

????? ???? 熟悉Content Provider(内容提供者)的应该知道,我们可以通过UriMatcher类注册不同类型的Uri,我们可以通过这些不同的

??? Uri来查询不同的结果。根据Uri返回的结果,Uri Type可以分为:返回多条数据的Uri、返回单条数据的Uri。

?

?

??注册/取消注册ContentObserver方法,抽象类ContentResolver类中的方法原型如下:

?

????public final void??registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)

???????????? 功能:为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理。

?????????? ??参数:uri??????????需要观察的Uri(需要在UriMatcher里注册,否则该Uri也没有意义了)

??????????????????? ????notifyForDescendents??为false 表示精确匹配,即只匹配该Uri

?????????????????????????????????????????????????????? ????????? ??? 为true 表示可以同时匹配其派生的Uri,举例如下:

??????????????????? ????? 假设UriMatcher 里注册的Uri共有一下类型:

??????????????????????????????? 1 、content://com.qin.cb/student (学生)

??????????????????????????????? 2 、content://com.qin.cb/student/#?

?????????????????????????????? ?3、?content://com.qin.cb/student/schoolchild(小学生,派生的Uri)

?

????????????????????假设我们当前需要观察的Uri为content://com.qin.cb/student,如果发生数据变化的?Uri?为???

?????????? content://com.qin.cb/student/schoolchild ,当notifyForDescendents为 false,那么该ContentObserver会监听不到,??

????????? ?但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。

?

???????????????????? observer????? ?ContentObserver的派生类实例

?

?

????public final void??unregisterContentObserver(ContentObserver?observer)

????????? 功能:取消对给定Uri的观察

????????? 参数: observer ContentObserver的派生类实例

?

????????

ContentObserver类介绍

?

??构造方法?public void?ContentObserver(Handler?handler)??

?????????????????????? 说明:所有?? ContentObserver的派生类都需要调用该构造方法

   ?    参数: handler  Handler对象。可以是主线程Handler(这时候可以更新UI 了),也可以是任何Handler对象。

?常用方法

?? void?onChange(boolean selfChange)

????? ?功能:当观察到的Uri发生变化时,回调该方法去处理。所有ContentObserver的派生类都需要重载该方法去处理逻辑。

???? ??参数:selfChange 回调后,其值一般为false,该参数意义不大(我也不懂,理解方法最重要)。

?

? 另外两个方法,用处不大,我也不懂,大家参照SDK自行理解,冒昧了。

? boolean??deliverSelfNotifications()

??? ?说明:Returns true if this observer is interested in notifications for changes made through the cursor the observer is registered with.

??

? final void?dispatchChange(boolean selfChange)

?

?

??观察特定Uri的步骤如下

?

??? ?1、??? 创建我们特定的ContentObserver派生类,必须重载父类构造方法,必须重载onChange()方法去处理回调后的功能实现

???? 2、??? 利用context.getContentResolover()获得ContentResolove对象,接着调用registerContentObserver()方法去注册内容观察者

???? 3、??? 由于ContentObserver的生命周期不同步于Activity和Service等,因此,在不需要时,需要手动的调用

?????????????unregisterContentObserver()去取消注册。 ???

?

?

?

好了,基本讲解就介绍到这儿了。下面给出小DEMO的简单说明:

???? Demo中共有两个不同的ContentObserver派生类,如下:

??????? 1、用来观察系统是否改变了飞行模式状态

????????? PS: 大家可以去SDK中查看该类:android.provider.Settings.System。该类封装了对设置模块下所有值的存取,比如:

???????? ?飞行模式状态、蓝牙状态、屏幕亮度值等,并且提供了相应的Uri。

????????2、观察系统的短信息数据发生了变化。当监听到短信数据发生变化时,查询所有已发送的短信并且显示出来。

?

?? 短信的Uri共有一下几种:

?????????????????????????content://sms/inbox? ???收件箱 ????????
?????????????????????????content://sms/sent????????已发送?
?????????????????????????content://sms/draft????? ??草稿 ??????????
???????????????????????? content://sms/outbox????发件箱?? ??????? (正在发送的信息)
?????????????????????????content://sms/failed??????发送失败?????
?????????????????????????content://sms/queued??待发送列表? (比如开启飞行模式后,该短信就在待发送列表里)

?

关于短信的更多内容可以参考该博客:<android 中管理短信>

?

????? 当开启飞行模式和发送短信后(注意:使用Home键退出,而不是Back键),DMEO截图如下:

?

???????????????

?

DEMO文件如下:

1、 观察飞行模式状态的ContentObserver派生类,AirplaneContentObserver.java

?

[java]?view plaincopyprint?
  1. package?com.qin.contentobserver;??
  2. ??
  3. import?android.content.Context;??
  4. import?android.database.ContentObserver;??
  5. import?android.net.Uri;??
  6. import?android.os.Handler;??
  7. import?android.provider.*;??
  8. import?android.provider.Settings.SettingNotFoundException;??
  9. import?android.util.Log;??
  10. ??
  11. ??
  12. //用来观察system表里飞行模式所在行是否发生变化?,?“行”内容观察者??
  13. public?class?AirplaneContentObserver?extends?ContentObserver?{??
  14. ??
  15. ????private?static?String?TAG?=?"AirplaneContentObserver"?;??
  16. ??????
  17. ????private?static?int?MSG_AIRPLANE?=?1?;??
  18. ??????
  19. ????private?Context?mContext;??????
  20. ????private?Handler?mHandler?;??//此Handler用来更新UI线程??
  21. ??????
  22. ????public?AirplaneContentObserver(Context?context,?Handler?handler)?{??
  23. ????????super(handler);??
  24. ????????mContext?=?context;??
  25. ????????mHandler?=?handler?;??
  26. ????}??
  27. ??
  28. ????/**?
  29. ?????*?当所监听的Uri发生改变时,就会回调此方法?
  30. ?????*??
  31. [email protected]下该回调值false?
  32. ?????*/??
  33. ????@Override??
  34. ????public?void?onChange(boolean?selfChange)?{??
  35. ????????Log.i(TAG,?"-------------the?airplane?mode?has?changed-------------");??
  36. ??????????
  37. ????????//?系统是否处于飞行模式下??
  38. ????????try?{??
  39. ????????????int?isAirplaneOpen?=?Settings.System.getInt(mContext.getContentResolver(),?Settings.System.AIRPLANE_MODE_ON);??
  40. ????????????Log.i(TAG,?"?isAirplaneOpen?----->?"?+isAirplaneOpen)?;??
  41. ????????????mHandler.obtainMessage(MSG_AIRPLANE,isAirplaneOpen).sendToTarget()?;??
  42. ????????}??
  43. ????????catch?(SettingNotFoundException?e)?{??
  44. ????????????//?TODO?Auto-generated?catch?block??
  45. ????????????e.printStackTrace();??
  46. ????????}??
  47. ??
  48. ????}??
  49. ??
  50. }??

?

????????

2、观察系统里短消息的数据库变化的ContentObserver派生类,SMSContentObserver.java

??

[java]?view plaincopyprint?
  1. package?com.qin.contentobserver;??
  2. ??
  3. import?android.content.Context;??
  4. import?android.database.ContentObserver;??
  5. import?android.database.Cursor;??
  6. import?android.net.Uri;??
  7. import?android.os.Handler;??
  8. import?android.util.Log;??
  9. ??
  10. ??
  11. //用来观察系统里短消息的数据库变化??”表“内容观察者,只要信息数据库发生变化,都会触发该ContentObserver?派生类??
  12. public?class?SMSContentObserver?extends?ContentObserver?{??
  13. ????private?static?String?TAG?=?"SMSContentObserver";??
  14. ??????
  15. ????private?int?MSG_OUTBOXCONTENT?=?2?;??
  16. ??????
  17. ????private?Context?mContext??;??
  18. ????private?Handler?mHandler?;???//更新UI线程??
  19. ??????
  20. ????public?SMSContentObserver(Context?context,Handler?handler)?{??
  21. ????????super(handler);??
  22. ????????mContext?=?context?;??
  23. ????????mHandler?=?handler?;??
  24. ????}??
  25. ????/**?
  26. ?????*?当所监听的Uri发生改变时,就会回调此方法?
  27. ?????*??
  28. [email protected]??下该回调值false?
  29. ?????*/??
  30. ????@Override??
  31. ????public?void?onChange(boolean?selfChange){??
  32. ????????Log.i(TAG,?"the?sms?table?has?changed");??
  33. ??????????
  34. ????????//查询发件箱里的内容???????
  35. ????????Uri?outSMSUri?=?Uri.parse("content://sms/sent")?;??
  36. ??????????
  37. ????????Cursor?c?=?mContext.getContentResolver().query(outSMSUri,?null,?null,?null,"date?desc");??
  38. ????????if(c?!=?null){??
  39. ??????????????
  40. ????????????Log.i(TAG,?"the?number?of?send?is"+c.getCount())?;??
  41. ??????????????
  42. ????????????StringBuilder?sb?=?new?StringBuilder()?;??
  43. ????????????//循环遍历??
  44. ????????????while(c.moveToNext()){??
  45. //??????????????sb.append("发件人手机号码:?"+c.getInt(c.getColumnIndex("address")))??
  46. //????????????????.append("信息内容:?"+c.getInt(c.getColumnIndex("body")))??
  47. //????????????????.append("是否查看:?"+c.getInt(c.getColumnIndex("read")))???
  48. //????????????????.append("发送时间:?"+c.getInt(c.getColumnIndex("date")))??
  49. //????????????????.append("\n");??
  50. ????????????????sb.append("发件人手机号码:?"+c.getInt(c.getColumnIndex("address")))??
  51. ??????????????????.append("信息内容:?"+c.getString(c.getColumnIndex("body")))??
  52. ??????????????????.append("\n");??
  53. ????????????}??
  54. ????????????c.close();????????????
  55. ????????????mHandler.obtainMessage(MSG_OUTBOXCONTENT,?sb.toString()).sendToTarget();??????????
  56. ????????}??
  57. ????}??
  58. ??????
  59. }??

?

?3、主工程逻辑为MainActivity.java,对短消息的观察Uri,通过测试我发现只能监听此Uri “content://sms” (等同于"content://sms/"),而不能监听其他的Uri,比如"content://sms/outbox"等。

?

[java]?view plaincopyprint?
  1. package?com.qin.contentobserver;??
  2. ??
  3. import?android.app.Activity;??
  4. import?android.database.Cursor;??
  5. import?android.net.Uri;??
  6. import?android.os.Bundle;??
  7. import?android.os.Handler;??
  8. import?android.os.Message;??
  9. import?android.provider.*;??
  10. import?android.util.Log;??
  11. import?android.widget.EditText;??
  12. import?android.widget.TextView;??
  13. ??
  14. public?class?MainActivity?extends?Activity?{??
  15. ??
  16. ????private?TextView?tvAirplane;??
  17. ????private?EditText?etSmsoutbox;??
  18. ??
  19. ????//?Message?类型值??
  20. ????private?static?final?int?MSG_AIRPLANE?=?1;??
  21. ????private?static?final?int?MSG_OUTBOXCONTENT?=?2;??
  22. ??
  23. ????private?AirplaneContentObserver?airplaneCO;??
  24. ????private?SMSContentObserver?smsContentObserver;??
  25. ??
  26. ????/**?Called?when?the?activity?is?first?created.?*/??
  27. ????@Override??
  28. ????public?void?onCreate(Bundle?savedInstanceState)?{??
  29. ????????super.onCreate(savedInstanceState);??
  30. ????????setContentView(R.layout.main);??
  31. ??
  32. ????????tvAirplane?=?(TextView)?findViewById(R.id.tvAirplane);??
  33. ????????etSmsoutbox?=?(EditText)?findViewById(R.id.smsoutboxContent);??
  34. ??
  35. ????????//?创建两个对象??
  36. ????????airplaneCO?=?new?AirplaneContentObserver(this,?mHandler);??
  37. ????????smsContentObserver?=?new?SMSContentObserver(this,?mHandler);??
  38. ??????????
  39. ????????//注册内容观察者??
  40. ????????registerContentObservers()?;??
  41. ????}??
  42. ??
  43. ????private?void?registerContentObservers()?{??
  44. ????????//?通过调用getUriFor?方法获得?system表里的"飞行模式"所在行的Uri??
  45. ????????Uri?airplaneUri?=?Settings.System.getUriFor(Settings.System.AIRPLANE_MODE_ON);??
  46. ????????//?注册内容观察者??
  47. ????????getContentResolver().registerContentObserver(airplaneUri,?false,?airplaneCO);??
  48. ????????//?”表“内容观察者?,通过测试我发现只能监听此Uri?----->?content://sms??
  49. ????????//?监听不到其他的Uri?比如说?content://sms/outbox??
  50. ????????Uri?smsUri?=?Uri.parse("content://sms");??
  51. ????????getContentResolver().registerContentObserver(smsUri,?true,smsContentObserver);??
  52. ????}??
  53. ??
  54. ????private?Handler?mHandler?=?new?Handler()?{??
  55. ??
  56. ????????public?void?handleMessage(Message?msg)?{??
  57. ??????????????
  58. ????????????System.out.println("---mHanlder----");??
  59. ????????????switch?(msg.what)?{??
  60. ????????????case?MSG_AIRPLANE:??
  61. ????????????????int?isAirplaneOpen?=?(Integer)?msg.obj;??
  62. ????????????????if?(isAirplaneOpen?!=?0)??
  63. ????????????????????tvAirplane.setText("飞行模式已打开");??
  64. ????????????????else?if?(isAirplaneOpen?==?0)??
  65. ????????????????????tvAirplane.setText("飞行模式已关闭");??
  66. ????????????????break;??
  67. ????????????case?MSG_OUTBOXCONTENT:??
  68. ????????????????String?outbox?=?(String)?msg.obj;??
  69. ????????????????etSmsoutbox.setText(outbox);??
  70. ????????????????break;??
  71. ????????????default:??
  72. ????????????????break;??
  73. ????????????}??
  74. ????????}??
  75. ????};??
  76. }??

?

? 在此基础上,你可以利用ContentObserver去实现短信黑名单以及悄悄发送短信等技巧,具体可以参考这篇博客:

????????????????< 接受指定号码的短信>

?

?总结: 使用ContentObserver的情况主要有一下两者情况:

???????? ??? ?1、需要频繁检测的数据库或者某个数据是否发生改变,如果使用线程去操作,很不经济而且很耗时 ;

???????????? ?2、在用户不知晓的情况下对数据库做一些事件,比如:悄悄发送信息、拒绝接受短信黑名单等;

?

? 在这两种情形下,使用ContentObserver无疑是最好的利刃了。

?

?? ?代码下载地址为:http://download.csdn.net/detail/qinjuning/3896987

?

?

原文地址:http://blog.csdn.net/qinjuning/article/details/7047607

  相关解决方案