先看图,因为这个DEMO是一个单线程,只是实现了观察者模式的基础,所以只有一个activity,并且代码不多
思路是这样的,通过观察者模式,监听SMS短信数据库的变化,从而完成一个数据自动加载的功能
这是Activity的展示,里面就一个EditText,测试的时候我会通过模拟器发送一条短信,然后这里会显示短信的内容,我就不贴xml代码了,只有一个控件
好了接下来就是主角登场,我一边贴代码,一边解释
private SMS_Observer smsObserver;
EditText et_input;
Handler handler;
ContentResolver resolver;
SMS_Observer是一个继承了ContentObserver的类,一会我会展开
ContentResolver是一会用来查询数据库的
还有一个Uri静态变量类,方便调用
public class UriContent {
//短信数据
public static String SMS = "content://sms";
//收件箱数据
public static String SMS_INBOX = "content://sms/inbox";
}
然后就是实例化我们所需要的元素
//handler创建,实现接口,返回值如果为false,表示不需要进行任何的处理,所以一般都返回true
handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if(msg.what == 100)
{
et_input.setText(msg.obj.toString());
}
return true;
}
});
//实例化
resolver = getContentResolver();
smsObserver = new SMS_Observer(handler, this);
这里大家看到Handller构造的时候需要一个Callback接口,并实例化
public interface Callback {
public boolean handleMessage(Message msg);
}
我们实例化的这个handleMessage函数,是用来接收我们刚刚创建的那个Handler变量的sendMessage函数,之后会看到。
我这里的理解就是自己发,自己收,因为Obersoer实例化的时候需要传入一个Handler。
然后就是注册了,如果不注册,他就无法监听数据库啦
//对观察者进行注册
//第一个参数:是一个Uri(Uri就是一个绝对路径)
//“content://sms”是短信的数据库
//“content://sms/inbox”是短信收件箱
//我会把这两个字段定义成一个类的静态成员方便调用
//第二个参数是个布尔值,表示是否递归,如果为true说明当前Uri路径下的任何变化都会捕捉,如果为false说明只捕捉当前的Uri路径,不包括子路径
//地三个参数就是一个观察者
resolver.registerContentObserver(Uri.parse("content://sms"), true, smsObserver);
/**
* 来理一下思路
* 首先在页面创建的时候,创建一个Observer,并通过resolver注册这个Observer,Observer被注册后,会监听给定URI路径下的数据,
* 如果数据发生变化,就会通过Observer里的handler进行处理
*/
参数我已经讲的很清楚了,就不一一解释了,然后有注册那就还会有销毁
@Override
protected void onDestroy() {
super.onDestroy();
resolver.unregisterContentObserver(smsObserver);
}
Activity的代码就解释完了,我把代码完整的发一遍
package com.ty.contentobserver_demo1;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.EditText;
import com.ty.contentobserver_demo1.util.Observer.SMS_Observer;
public class MainActivity extends AppCompatActivity {
private SMS_Observer smsObserver;
EditText et_input;
Handler handler;
ContentResolver resolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_input = (EditText) findViewById(R.id.ET_Main_Input);
//handler创建,实现接口,返回值如果为false,表示不需要进行任何的处理,所以一般都返回true
handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if(msg.what == 100)
{
et_input.setText(msg.obj.toString());
}
return true;
}
});
//实例化
resolver = getContentResolver();
smsObserver = new SMS_Observer(handler, this);
//对观察者进行注册
//第一个参数:是一个Uri(Uri就是一个绝对路径)
//“content://sms”是短信的数据库
//“content://sms/inbox”是短信收件箱
//我会把这两个字段定义成一个类的静态成员方便调用
//第二个参数是个布尔值,表示是否递归,如果为true说明当前Uri路径下的任何变化都会捕捉,如果为false说明只捕捉当前的Uri路径,不包括子路径
//地三个参数就是一个观察者
resolver.registerContentObserver(Uri.parse("content://sms"), true, smsObserver);
/**
* 来理一下思路
* 首先在页面创建的时候,创建一个Observer,并通过resolver注册这个Observer,Observer被注册后,会监听给定URI路径下的数据,
* 如果数据发生变化,就会通过Observer里的handler进行处理
*/
}
@Override
protected void onDestroy() {
super.onDestroy();
resolver.unregisterContentObserver(smsObserver);
}
}
第二部分,也就是SMS_Observer这个类,既然监听回掉的是Observer的OnChange这个函数,自然我们要重写一下这个函数,告诉他应该做点啥
1、我们先看SMS_Observer这个类的变量和构造函数
private ContentResolver resolver;
private Handler handler;
public SMS_Observer(Handler handler, Context context) {
super(handler);
resolver = context.getContentResolver();
this.handler = handler;
}
Resolver我就不具体讲了,之前一片博客已经写过了。
然后就是onChange这个函数的重写
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Cursor cursor = resolver.query(Uri.parse(UriContent.SMS_INBOX), new String[]{"body"}, null, null, "date desc");
if(cursor != null)
{
if(cursor.moveToFirst())
{
String smsBody = cursor.getString(0);
Message msg = Message.obtain();
msg.what = 100;
msg.obj = smsBody;
handler.sendMessage(msg);
cursor.close();
}
}
}
重点其实就是只有一句话
handler.sendMessage(msg);先定义一个Message然后赋值最后发送
说是发送,其实就是加入一个消息的队列
我们之前的那个handleMessage函数一直在查询队列里有没有消息
我再把他贴上来对比一下
public boolean handleMessage(Message msg) { if(msg.what == 100) { et_input.setText(msg.obj.toString()); } return true; }大家这下应该就差不多清楚了,应为我其实还没学习到怎么熟练的使用handler,这篇就当是一个引导,之后还会有更详细更深入的讲解
我再把代码贴一下这个类的完整代码贴一下
package com.ty.contentobserver_demo1.util.Observer;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import com.ty.contentobserver_demo1.util.Observer.Uri.UriContent;
/**
* Created by IT on 2017/2/23.
*/
public class SMS_Observer extends ContentObserver {
private ContentResolver resolver;
private Handler handler;
public SMS_Observer(Handler handler, Context context) {
super(handler);
resolver = context.getContentResolver();
this.handler = handler;
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Cursor cursor = resolver.query(Uri.parse(UriContent.SMS_INBOX), new String[]{"body"}, null, null, "date desc");
if(cursor != null)
{
if(cursor.moveToFirst())
{
String smsBody = cursor.getString(0);
Message msg = Message.obtain();
msg.what = 100;
msg.obj = smsBody;
handler.sendMessage(msg);
cursor.close();
}
}
}
}
好了 我还会回来的