在一些应用上,比如手机银行,QQ,微信等,很多时候我们都需要通过发送验证码到手机上,然后把验证码填上去,然后才能成功地继续去做下面一步事情。

而如果每次我们都要离开当前界面,然后去查收短信,记住验证码,然后再回来输入到控件中,这感觉就会很麻烦,用户体验就会很差,而像微信等一些应用,则会在手机接到短信后,将信息中的验证码给抽出来,帮我们将其填到对应的控件中,多方便,对吧。

这个功能就是通过ContentObserver来实现的。顾名思义,Content Observer,就是内容监听,它实现的功能就是对特定的Uri进行监听,当监听的Uri发生变化时,就能够根据开发者的意思去做相应的处理。

下面我们就利用一个小小的Demo来简单地看一下,Content Observer是如何应用的。

这个小Demo的功能就是会监听短信的到达,然后将短消息里面的内容放到一个TextView上面展示,具体效果如下面的GIF图片:

具体的步骤如下:

1)自定义一个类,它要继承ContentObserver类,并且实现其onChange方法:

public class SMSContentObserver extends ContentObserver{private static final String TAG = "com.lms.codemo.SMSContentObserver";private Handler mHandler;private Context mContext;private ContentResolver mContentResolver;private Uri uri = Uri.parse("content://sms/inbox");private int mMsgCode;public SMSContentObserver(Handler handler) {super(handler);this.mHandler = handler;}public SMSContentObserver(Handler handler, Context context, int msgCode){super(handler);this.mHandler = handler;this.mContext = context;this.mMsgCode = msgCode;mContentResolver = mContext.getContentResolver();        }public void onChange(boolean selfChange) {super.onChange(selfChange);String[] projection = new String[] {"_id","address","body","type"};Cursor cursor = mContentResolver.query(uri, projection, null, null, "date desc");if(cursor == null){}else if(!cursor.moveToFirst()){}else{do{String msgBody = cursor.getString(cursor.getColumnIndex("body"));int msgId = cursor.getInt(cursor.getColumnIndex("_id"));String msgAddr  = cursor.getString(cursor.getColumnIndex("address"));String msgType  = cursor.getString(cursor.getColumnIndex("type"));Log.v(TAG, "msgId : " + msgId);Log.v(TAG, "msgAddr : " + msgAddr);Log.v(TAG, "msgBody : " + msgBody);Log.v(TAG, "msgType : " + msgType);Message message = Message.obtain();message.what = mMsgCode;message.obj = msgBody;mHandler.sendMessage(message);break;}while(cursor.moveToNext());cursor.close();}        }}

这个SMSContentObserver继承了ContentObserver,并且定义了一个包含context,handler和msgCode的构造函数,其中

1.1)context是为获得ContentResolver来查询系统短消息的Uri,

1.2)handler是为了将获取到的内容发送回UI线程,进行UI的更新,

1.3)msgCode是handler处理的消息代码,表明是处理短消息的消息。

ContentObserver的原理其实就在于监听指定Uri的变化,在这个类中,因为我们是要获取收到的短消息的内容,所以在这里要去查询短消息收件箱的内容,其URI定义如下:

private Uri uri = Uri.parse("content://sms/inbox");

当指定的Uri变化了,ContentObserver就会调用其onChange函数,我们可以看到在ContentObserver类中的关于onChange函数的定义:

    /*** This method is called when a content change occurs.* <p>* Subclasses should override this method to handle content changes.* </p>** @param selfChange True if this is a self-change notification.*/public void onChange(boolean selfChange) {// Do nothing.  Subclass should override.}

在这里指出,这个方法就是在内容改变的时候会被调用,同时要求这个函数必须由子类来实现,因为具体的逻辑是我们自己来定义的。

在Onchange函数中,我们会通过context获得ContentResolver,按照日期的返序获得第一条短消息,然后通过Handler发送到UI主线程。真正在实际上应用的逻辑会更复杂,而不是单纯地将内容返回去,我们可以看到短消息的有几个主要的字段:

a)type,表明是发送(2)还是接收(1)

b)address,对应的号码

c)body,对应的消息内容

d)date,对应的日期

等等。

2)我们要将这个ConentObserver注册到对应的Context中,就跟注册广播一样啊,要在某个地方告诉系统,如果短消息内容变化了,你要告诉我一下,我好处理事情,对吧。

这个小demo里面,就是我们的主界面,MainActivity了,代码如下:

public class MainActivity extends Activity{private static final String TAG = "com.lms.codemo.MainActivity";private TextView tvShowMsg;private SMSContentObserver smsContentObserver;private static final int MSG_CODE = 1;private Handler mHandler = new Handler(){public void handleMessage(Message msg){if( MSG_CODE == msg.what){              String msgBody = (String) msg.obj;Log.v(TAG, "msg_body: " + msgBody);tvShowMsg.setText(msgBody);}}};protected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tvShowMsg = (TextView)findViewById(R.id.tvShowMsg);smsContentObserver = new SMSContentObserver(mHandler,this,MSG_CODE);getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, smsContentObserver);}protected void onDestroy(){super.onDestroy();getContentResolver().unregisterContentObserver(smsContentObserver);;}

2.1)在Activity中,我们主要就是创建了一个handler对象,将其还有context传给SMSContentObserver,这样,它才能将消息给传回来,在主线程中处理,处理很简单,将返回来的消息内容直接更新到TextView上面。

2.2)在Activity创建的时候,我们要创建实例化一个SMSContentObserver,然后调用ContentResolver的registerContentObserver方法,将指定的Uri绑定给它,这样,SMSContentObserver才知道它是要去监听这个Uri的内容,而在这里,当然就是监听短消息的内容了,如下:

Uri.parse("content://sms")

2.3)我们看一下这个函数的定义:

    /*** Register an observer class that gets callbacks when data identified by a* given content URI changes.** @param uri The URI to watch for changes. This can be a specific row URI, or a base URI* for a whole class of content.* @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>* will also cause notifications to be sent. If <code>false</code> only changes to the exact URI* specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values* at or below the specified URI will also trigger a match.* @param observer The object that receives callbacks when changes occur.* @see #unregisterContentObserver*/public final void registerContentObserver(Uri uri, boolean notifyForDescendents,ContentObserver observer){registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());}

其中,中间这个参数notifyForDescendents的值如果为true呢,那么所有以指定Uri开头的Uri发生变化,都会触发指定的ContentObserver,就比如我们demo中,我们监听的其实是

“content://sms”,但其实真正变化的是,"conent://sms/inbox",但是因为我们设置为true了,所以我们就能够触发对应的事件,相反,如果设置为false,就不行了。

2.4)最后,如果我们不需要去监听内容的变化了,我们就要把它注销掉,跟广播其实一样的。

结束。源代码点击下载

Android学习小Demo(13)Android中关于ContentObserver的使用相关推荐

  1. Android学习小Demo(10)ToDoList的改进版之ViewPager显示多个图片

    在TodoList增强版的增加界面上,为了显示图片,我是挖了两块地方,放了两个ImageButton,来显示图片,而且限制了最多只能放两张图片.当两个View都放置图片之后,我就会把"Gal ...

  2. Android学习小Demo(10)ToDoList的加强版

    前两天去超市逛东西,问老板娘这个东西多少钱,那个东西多少钱,但是一两分钟后就搞混了,当时就想,我不是写了一个todo的吗,可以再拍照放上去,这样就有对比啦! 于是兴冲冲地赶回家,把功能给实现了,虽然这 ...

  3. Android学习小Demo(9)一个To Do List的实现

    记得看过一篇文章,是说一个人临走之前,列下了想做的最后100件事情,然后拿着这张便签,一件一件地去实现.又想起乔布斯说,如果今天是你的最后一天,你会怎么过? 我有很多事情想做,想写很多的文章,但是时间 ...

  4. Android学习小Demo(12)TodoList实现ListView的分组实现

    很多情况下, 我们想要ListView上面展示的东西是可以分组的,比如联系人列表,国家列表啊,这样看起来数据的展现比较有层次感,而且也有助于我们快速定位到某一个具体的条目上,具体效果请看下图: 这是前 ...

  5. Android学习小Demo(11)一个显示行线的自定义EditText

    今天在处理一个EditText的时候,想着把EditText做成像一本作业本上的纸一样,每一行都可以由线条隔开,具体效果如下: 1)最开始的思路 一开始的想法是很简单的,找出每一行的高度,然后一行一行 ...

  6. Android学习小Demo(14)Android中关于PopupWindow的使用

    在一些场景中,我们希望能够点击按钮, 然后弹出一个菜单,而这个菜单是显示在屏幕的中央的,那么在Android中可以通过PopupWindow来实现这个效果. 具体效果如下图: 如上图中,我们点击&qu ...

  7. Android学习笔记07---查看Android虚拟机输出的错误信息与如何部署应用到自己的真实手机

    Android学习笔记07---查看Android虚拟机输出的错误信息

  8. Android学习笔记----解决“com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536”问题

    Android学习笔记----解决"com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 6553 ...

  9. Android计步器小Demo

    描述 android计步器的实现,自定义的一个弧形进度条,记步通过手机的传感器来实现,也就是说不支持传感器的机子(应该很老的了吧)就没有效果.看看效果图: 自定义View public class S ...

最新文章

  1. ajax校验用户名可用吗,基于jQuery实现Ajax验证用户名是否可用实例
  2. ascii modbus vc源码_MODBUS ASCII及MODBUS RTU通讯
  3. oem是代工还是贴牌_食用油OEM贴牌代工业务要注意哪些问题?
  4. I2C总线学习—查缺补漏—应答信号ACK
  5. python中is、id、==与浅拷贝和深拷贝
  6. JavaScript之基础-9 JavaScript String(内置对象、String概述、字符串常用操作、模式匹配)...
  7. Linux根目录下的各个子目录的作用
  8. springboot++vue+elementui网上零食购物商城网站系统带统计投诉java
  9. 日记侠:如何提高朋友圈活跃度,给你5种实用方法
  10. 【漏洞复现-coldfusion-文件读取】vulfocus/coldfusion-cve_2010_2861
  11. 2023年天津仁爱学院高职升本科专业考试报考须知
  12. 牛客网力扣算法编程之二十一 | 数组 - 明明的随机数 - Java代码实现
  13. pl330 dmac驱动分析2----关键函数
  14. 初学安装oracle11g遇到的问题,以及解决方案
  15. ASP.NET Core 集成AAD认证在Docker中运行时要注意的一个问题
  16. linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
  17. python爬虫读取pdf_python爬虫处理在线预览的pdf文档
  18. 使用python异步框架aiohttp从NASA抓取火星图片
  19. Lamdba及DataTable AsEnumerable()的使用
  20. c语言三阶幻方问题(回溯)

热门文章

  1. 被外包程序员植入了后门程序,触发后删除数据库但他们死不承认,该怎么办?...
  2. JavaSE: SuppressWarnings[转]
  3. Jenkins动态部署方案
  4. android技术总结
  5. Day 41 Rsync备份
  6. 是什么构成了“人工智能”热潮?
  7. hadoop学习笔记(四):hdfs常用命令
  8. yii2 Rbac使用yii命令一键建表
  9. Troubleshooting OpenStack 瘫痪 - 每天5分钟玩转 OpenStack(160)
  10. Linux发展历史图