第四篇就来总结下项目中使用到的一个提升用户体验的功能: Android自动填写验证码
从字面上来看,很明显的可以看出它的实现流程:监听->有改变->获取信息->改变ui
观察者模式
观察者模式是软件设计模式中的一种,在此模式中,一个目标物件管理所有相依于它的观察者物件,并且在本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统
观察者模式Observer完美的将观察者和被观察的对象分离开,在模块之间划定接线,提高应用程序的可维护性和重用性。同时定义了对象间一种一对多的以来关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
观察者:Observer将自己注册到被观察对象中,被观察对象将观察者存放在一个容器里
被观察:当被观察者对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者
撤销观察:观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除
ContentObserver
内容观察者,目的是观察捕捉特定uri引起的数据库的变化,继而做一些相应的处理,类似于数据库中的触发器。
流程如下:
1. 创建ContentObserver派生类,重载onChange()方法处理回调。
2. 利用context.getContentResolover() 获得ContentResolove对象,调用registerContentObserver()方法去注册
3. 在不需要使用时(例如验证码获取成功后),调用unregisterContentObserver()取消注册
实现
在我们创建的SmsObserver类中,必须要实现onChange方法,这是一个检测uri是否变化的方法。
而验证短信发来的时候,会调用两次,第一次的uri会提示raw,此时只是表示短信到了,还没有写入数据库中。而第二次变化的时候才是我们需要接收与检测的,此时才表示短信已经被写入了数据库中。
而对于相关验证码的提取,使用正则表达式的方式,获取连续的4个数字(根据自己的需要)。
另外,在AndroidManifest文件中添加Read_SMS的权限
相关代码如下:
package com.screform.mmd.customview;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;
import com.screform.mmd.aty.Aty_Register;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by lizhongquan on 15-11-18.
* Class to Observer the sms and notify to setText in editText_IdentifyingCode
*/
public class SmsObserver extends ContentObserver {
private Context context;
private Handler handler;
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public SmsObserver(Context context, Handler handler) {
super(handler);
this.context = context;
this.handler = handler;
}
/**
* code ChangeListener
*
* @param selfChange change or not
* @param uri the uri of event
*/
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.d("info", "SMS is changed");
Log.d("info", uri.toString());
// When the sms is coming, it will be change twice.
// the first time change is not the one we need.
// The sms is not writed into the database in this time
if (uri.toString().equals("content://sms/raw")) {
return;
}
// handle the second change
// get the inboxUri
Uri inboxUri = Uri.parse("content://sms/inbox");
// query the inbox
// get the sms
Cursor mCursor = context.getContentResolver().query(inboxUri, null, null, null, "date desc");
if (null != mCursor) {
if (mCursor.moveToFirst()) {
String address = mCursor.getString(mCursor.getColumnIndex("address"));
String body = mCursor.getString(mCursor.getColumnIndex("body"));
Log.d("info", "address is :" + address + ", body is " + body);
if (address.equals("106900321100")) {
// use a regular expression to resolve and get the identifying code
// get the four consecutive numbers
Pattern pattern = Pattern.compile("(\\d{4})");
Matcher matcher = pattern.matcher(body);
if (matcher.find()){
Log.d("info", "Identifying code is " + matcher.group(0));
handler.obtainMessage(Aty_Register.GETSMS, matcher.group(0))
.sendToTarget();
}
}
}
}
// close mCursor
mCursor.close();
}
}
在Aty_Register.java中:
initObserver():
Uri uri = Uri.parse("content://sms");
smsObserver = new SmsObserver(Aty_Register.this, handler);
getContentResolver().registerContentObserver(uri, true, smsObserver);
onStop()中: 取消注册
@Override
protected void onStop() {
super.onStop();
getContentResolver().unregisterContentObserver(smsObserver);
Log.d("info", "unregister");
}
handler中: 更新UI
case GETSMS:
editText_IdentifyingCode.setText(msg.obj.toString());
break;
AndroidManifest:
<uses-permission android:name="android.permission.READ_SMS" />