我的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的东西

0 0
原创粉丝点击