您的位置:首页 > 移动开发 > Android开发

我的Android心得(4)--监听电话和短信是否来自关注对象--contentObserver

2014-05-23 12:41 375 查看
目标:在做毕业设计,要实现当手机有未接短信或者未接来电,并且来源号码是特定的一个关注对象时,触发提醒。

一开始是想用BroadcastReceiver,有短信、来电时Android系统会发出广播,我们只要注册一个BroadcastReceiver接收这些广播,在onReceive方法里面判断一些是否来自关注对象即可。

关于BroadcastReceiver,这篇文章讲的很细致 /article/5705168.html

注意的是BroadcastReceiver在onReceive方法里不能进行耗时的操作,Receiver也要在manifest里面注册

BroadcastReceiver的广播事件不仅有系统的事件,还可以应用自定义的广播事件。

以下是我的实现

PhoneBroadcastReceiver.java 文件:

public class PhoneBroadcastReceiver extends BroadcastReceiver {

// broadcast intent位于主线程,不能再onReceive执行太多操作,太多操作要开个Service
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(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 {

@Override
public 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

这里给出监测来电的代码 /article/7562114.html

这里关于ContentObserver讲的比较详细 /article/4997788.html

我的实现是,开启一个Service,在Service中注册ContentObserver,就可以在退出该软件之后仍然监视着。经过我的小米手机实测,当你手动杀掉进程,该Service会被kill掉,即这时候无法监测来电和短信,但是过几分钟后该Service又能够开启

MissedCallOrSMSService.java,为了让Service重新start时又能观察内容,我不断地register和unregister

public class MissedCallOrSMSService extends Service{

private MissedCallContentObserver call;
private MissedSMSContentObserver sms;

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.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);

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub

this.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);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.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的东西
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: