我的Android心得(4)--监听电话和短信是否来自关注对象--contentObserver
来源:互联网 发布:农村淘宝进驻地区查询 编辑:程序博客网 时间:2024/05/16 14:47
目标:在做毕业设计,要实现当手机有未接短信或者未接来电,并且来源号码是特定的一个关注对象时,触发提醒。
一开始是想用BroadcastReceiver,有短信、来电时Android系统会发出广播,我们只要注册一个BroadcastReceiver接收这些广播,在onReceive方法里面判断一些是否来自关注对象即可。
关于BroadcastReceiver,这篇文章讲的很细致 http://www.cnblogs.com/alwaysyouare/archive/2011/11/17/2252397.html
注意的是BroadcastReceiver在onReceive方法里不能进行耗时的操作,Receiver也要在manifest里面注册
BroadcastReceiver的广播事件不仅有系统的事件,还可以应用自定义的广播事件。
以下是我的实现
PhoneBroadcastReceiver.java 文件:
public class PhoneBroadcastReceiver extends BroadcastReceiver {// broadcast intent位于主线程,不能再onReceive执行太多操作,太多操作要开个Service@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubif(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){// 有电话打出去}else{// 有电话打进来// 取得telephony服务TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);// 监听电话MyPhoneStateListener my = new MyPhoneStateListener();my.mContext = context;telephonyManager.listen(my, PhoneStateListener.LISTEN_CALL_STATE);}}private class MyPhoneStateListener extends PhoneStateListener{Context mContext = null;public void onCallStateChanged(int state,String incomingNumber){//关注对象的电话号码String targetPhoneNumber = new Target(this.mContext).getInfo(Target.TargetPhoneNumber);if(state == TelephonyManager.CALL_STATE_RINGING && incomingNumber.equals(targetPhoneNumber)){// 触发提醒功能,在这里添加代码}super.onCallStateChanged(state, incomingNumber); } }}
SMSBroadcastReceiver.java
public class SMSBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stub// 取出所有短信Object[] pdusData = (Object[])intent.getExtras().get("pdus");for(int i = 0; i<pdusData.length; ++i){SmsMessage smsMessage = SmsMessage.createFromPdu((byte[])pdusData[i]);String phoneNumber = smsMessage.getOriginatingAddress();String targetPhoneNumber = new Target(context).getInfo(Target.TargetPhoneNumber);//关注对象的电话号码if(phoneNumber != null && phoneNumber.equals(targetPhoneNumber)){//触发提醒,在这里添加代码}}}}
AndroidManifest.xml要注册Receiver
<span style="white-space:pre"></span><receiver android:name="com.example.mytest.SMSBroadcastReceiver" > <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> <receiver android:name="com.example.mytest.PhoneBroadcastReceiver" > <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- 定义开机即启动 --> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver>
要用到的permission
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
这样实现的结果是一有短信或者一有电话,就触发提醒,所以有时候来电话响铃了,我已经准备接了,但它还提醒,我不得不关了提醒才能接电话。我要的是我有电话忘记接了,而且这来电是关注对象的,软件才要提醒我。所以BroadcastReceiver实现是不够完美的。
知道了来电短信都记录在Android中的数据库中,我们只要关注未接来电、未读短信的数据库有变化时,去检查号码是否为关注对象的即可,这时候用ContentObserver
这里给出监测来电的代码 http://chunpeng.iteye.com/blog/523728
这里关于ContentObserver讲的比较详细 http://www.cnblogs.com/slider/archive/2012/02/14/2351702.html
我的实现是,开启一个Service,在Service中注册ContentObserver,就可以在退出该软件之后仍然监视着。经过我的小米手机实测,当你手动杀掉进程,该Service会被kill掉,即这时候无法监测来电和短信,但是过几分钟后该Service又能够开启
MissedCallOrSMSService.java,为了让Service重新start时又能观察内容,我不断地register和unregister
public class MissedCallOrSMSService extends Service{private MissedCallContentObserver call;private MissedSMSContentObserver sms;@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();call = new MissedCallContentObserver(this, new Handler());sms = new MissedSMSContentObserver(this, new Handler());// 在服务创建的时候注册ContentObserver,之后就会一直存在this.getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, false, call); // 发现uri为content://sms/inbox无效,true表示同时监听子目录变化this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, sms); }@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubthis.getContentResolver().unregisterContentObserver(call);this.getContentResolver().unregisterContentObserver(sms);this.getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, false, call);this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, sms);return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();this.getContentResolver().unregisterContentObserver(call);this.getContentResolver().unregisterContentObserver(sms);}}//当有call log时,就会对这个类进行回调 class MissedCallContentObserver extends ContentObserver { private Context ctx; private Target target; public MissedCallContentObserver(Context context, Handler handler) { super(handler); ctx = context; target = new Target(ctx); } @Override public void onChange(boolean selfChange) { Cursor csr = ctx.getContentResolver().query(Calls.CONTENT_URI, new String[] {Calls.NUMBER, Calls.TYPE, Calls.NEW}, null, null, Calls.DEFAULT_SORT_ORDER); if (csr != null) { if (csr.moveToFirst()) { int type = csr.getInt(csr.getColumnIndex(Calls.TYPE)); switch (type) { case Calls.MISSED_TYPE: if (csr.getInt(csr.getColumnIndex(Calls.NEW)) == 1 && csr.getString(csr.getColumnIndex(Calls.NUMBER)).equals(target.getInfo(Target.TargetPhoneNumber))) { Log.e("eee", target.getInfo(Target.TargetName) + " 打来未接电话"); Intent intent = new Intent(ctx, RemindService.class); intent.putExtra("remind_kind", "有未接电话啊!"); ctx.startService(intent); } break; case Calls.INCOMING_TYPE: break; case Calls.OUTGOING_TYPE: break; } } // release resource csr.close(); } } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } } class MissedSMSContentObserver extends ContentObserver { private Context ctx; private Target target; public MissedSMSContentObserver(Context context, Handler handler) { super(handler); ctx = context; target = new Target(ctx); } @Override public void onChange(boolean selfChange) { // select _id, address, read from Uri where read = 0, 0 是未读 Cursor csr = ctx.getContentResolver().query(Uri.parse("content://sms/inbox"), new String[]{"_id", "address", "read"}, "read=?", new String[]{"0"}, "date desc"); if (csr != null) { if (csr.moveToFirst()) { if(csr.getString(csr.getColumnIndex("address")).equals(target.getInfo(Target.TargetPhoneNumber))){ Log.e("eee", target.getInfo(Target.TargetName) + " 发来短信"); // 提醒响铃 Intent intent =new Intent(ctx, RemindService.class); intent.putExtra("remind_kind", "有未接短信啊!"); ctx.startService(intent); } } // release resource csr.close(); } } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } }
在Manifest里面注册
<service android:name="com.example.mytest.MissedCallOrSMSService"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/> <uses-permission android:name="android.permission.READ_SMS"/>这时候效果能够与我们想要的一样了。
还是感谢一开始想错方向,学到了不少BroadcastReceiver的东西
- 我的Android心得(4)--监听电话和短信是否来自关注对象--contentObserver
- android ContentObserver监听系统短信和备份短信到本地
- ContentObserver监听发送的短信
- Android 监听短信2种方式:Broadcast和ContentObserver
- Android两种方式监听短信内容---BroadcastReceiver和ContentObserver
- Android ContentObserver监听短信提取验证码
- 使用ContentObserver监听短信数据库的变化
- 使用ContentObserver监听短信
- 使用ContentObserver监听短信
- ContentObserver短信监听
- 使用ContentObserver监听短信
- android 短信,电话监听广播
- Android电话监听与短信监听
- Android监听数据表(ContentObserver)
- Android 使用ContentObserver监听短信的变化,并发送信息给特定的手机号码
- Android电话及短信的监听程序源码
- Android中监听电话接听拨打、收发短信的实例
- 【android】利用ContentObserver监听短信来获取验证码
- 在Hibernate中处理批量更新和批量删除
- linux uniq命令详解
- struts2标签
- 自己写的一个php基于phpQuery的通用采集类
- 开发量考虑对方门将你看到你犯了难
- 我的Android心得(4)--监听电话和短信是否来自关注对象--contentObserver
- OCP 1Z0 051 96
- JavaScript事件机制详细研究
- c#绘图技术
- Python模块学习 ---- pickle, cPickle 对象序列化/反序列化
- 一个很好用的中文语音播报接口
- Notepad++插件TextFX的下载和使用
- LeetCode: N-Queens II [051]
- Handy adb commands for Android