在一些应用上,比如手机银行,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)最后,如果我们不需要去监听内容的变化了,我们就要把它注销掉,跟广播其实一样的。
结束。源代码点击下载
分享到:
相关推荐
很可能包含了一个关于Observer模式的实战例子,可能涵盖了ContentObserver和BroadcastReceiver的使用,通过查看这个示例项目,你可以更深入地理解如何在Android应用中实现Observer模式,以及如何在实际项目中灵活...
通过分析和学习这个demo,你可以快速掌握在Android应用中集成日历功能的方法。在实际项目中,可以根据需求进一步定制日历界面,比如添加滑动切换月份的功能,或者添加事件的拖放编辑等。 总之,Android日历功能的...
总之,"android——手机通讯录Demo"项目涵盖了Android开发中的多个关键知识点,包括系统API的使用、UI设计、数据管理以及性能优化,是提升Android开发者技能的绝佳实践。通过这个项目,开发者可以深入理解Android...
在Android系统中,广播(Broadcast)...通常,更推荐使用其他组件如Service或ContentObserver来实现类似功能。同时,由于Android系统的更新和安全性的提升,对Home键的监听可能在未来的版本中变得更为困难或不被允许。
"Content Observer Demo 源代码" 是一个关于Android开发的示例项目,它演示了如何使用ContentObserver类来监听系统中的数据变化,特别是与短信(SMS)相关的数据变化。在这个项目中,开发者可以学习到如何实时监控...
本项目"Android异步加载-demo-mesmall"是一个示例,旨在演示如何在Android应用中实现异步加载,主要涵盖了三种常见的异步加载方法:AsyncTask、Handler和Loader。 首先,我们来看**AsyncTask**。AsyncTask是Android...
在Android开发中,ContentProvider是一种重要的组件,它允许应用程序间共享数据。...通过实践这两个Demo,开发者可以深入理解ContentProvider的工作机制,从而在实际项目中更有效地使用这一功能强大的组件。
本项目适用于初学者进行Android开发的学习,通过这个Demo,你可以深入理解Android应用的基本架构和核心功能实现。 在Android开发中,首要掌握的是Android SDK(Software Development Kit),它是开发Android应用的...
在Android开发中,多线程下载和断点续传是提高用户下载体验的重要技术。本文将深入探讨如何在Android环境中实现这一功能,并...在DownloadDemo这个示例项目中,可以找到具体的代码实现和细节处理,供开发者参考学习。
总的来说,这个Demo可以帮助开发者学习如何在Android应用中实现一个类似系统图库的照片墙画廊,包括使用`RecyclerView`构建布局,使用`MediaStore`访问媒体文件,以及加载和管理图片的策略。开发者可以通过阅读和...
在这个名为 "GreenDaoDemo" 的项目中,我们将深入探讨如何在 Android 应用程序中使用 GreenDao 进行数据存储,并展示如何与 `ListView` 配合显示数据。 1. **GreenDao 概述** GreenDao 提供了一种高效且易于使用的...
ContentObserver是一个Android提供的接口,用于监听Android系统中特定Uri指向的数据变化。当数据发生变化时,ContentObserver会接收到通知并调用onChange()方法。在这个例子中,我们创建了一个名为...
总结,ContentProvider是Android中实现数据共享的重要机制,理解和掌握它的使用能够帮助开发者构建更加健壮、功能丰富的应用程序。通过合理的权限控制和优化,ContentProvider可以在保证数据安全的同时,实现高效的...
在Android中,可以使用`Intent`来启动系统的相机应用。通过`ACTION_IMAGE_CAPTURE` Intent,我们可以启动相机并获取拍摄的照片。完成拍摄后,照片会通过`onActivityResult`回调返回。 2. **访问相册** 访问用户的...
在Android应用开发的过程中,经常需要编写各种功能性的代码片段来实现特定的功能需求。以下是从一篇名为“20个Android很有用的代码片段”的文章中提取的一些关键代码段及其解释。这些代码片段不仅能够帮助开发者快速...