通过本案例,主要学习以下几点:
(1)通过查看api文档,找到实现相应功能所需要的,intent的action属性,其对应的extra字段,以及所需要的相关权限。
(2)对于仅在后台运行的服务,如何开启。例如本案例并没有前台界面,仅仅需要在后台开启一个servcie进行实时监听,然而service需要启动时机,因此考虑利用广播来启动。监听系统开机的广播事件,在其receive方法中,开启后台服务。(考虑过如果仅仅监听来电,是否可以在onreceive方法中之间为系统的telephoneService设置对应的监听事件,不过这种方法,总比不上自己重写一个服务更优美《一方面因为onrecive的周期大概10秒左右,另一方面,添加监听事件一般仅需要一次,没有必要每一次onreceive都为其设置监听事件,多次设置甚至会出错?,后来在api文档中发现这么一句话,不知道是不是由于这个原因:
In particular, you may not show a dialog or bind to a service from within a BroadcastReceiver. For the former, you should instead use the NotificationManager
API. For the latter, you can use Context.startService()
to send a command to the service》)。这个思路很重要,可以用在自己的项目中需要开启服务向服务器段上传数据的需求中。
首先看配置文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.lxh.demo" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <receiver android:name=".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> <service android:name=".PhoneService" /> </application> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> </manifest>
之前总是感觉很神奇,不知到这些action字段、权限字段从何而来,因为纯粹是经验的积累,其实这些在api文档中都能找到。
接着看receiver的实现类:
package org.lxh.demo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class PhoneBroadcastReceiver extends BroadcastReceiver { // ¹ã²¥ŽŠÀí @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals( Intent.ACTION_NEW_OUTGOING_CALL)) { // È¥µç²Ù×÷ String outgoingNumber = intent .getStringExtra(Intent.EXTRA_PHONE_NUMBER); // È¡µÃÈ¥µçºÅÂë Intent pit = new Intent(context, PhoneService.class); // ¶šÒåIntent pit.putExtra("outgoingNumber", outgoingNumber); // ±£ŽæÈ¥µçºÅÂë context.startService(pit); // Æô¶¯Service } else { // ÀŽµç context.startService(new Intent( context, PhoneService.class)); // Æô¶¯Service } } }
不要在receiver中进行复杂的操作,如本例子中,仅仅是开启对应的服务。
之后就是自己编写的服务类:
package org.lxh.demo; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; public class PhoneService extends Service { private TelephonyManager telephony = null; // µç»°¹ÜÀíÆ÷ private String outgoingNumber = null; // ±£ÁôÈ¥µçºÅÂë @Override public void onCreate() { this.telephony = (TelephonyManager) super .getSystemService(Context.TELEPHONY_SERVICE); // È¡µÃ·þÎñ this.telephony.listen(new PhoneStateListenerImpl(), PhoneStateListener.LISTEN_CALL_STATE); // ÉèÖõ绰ŒàÌý super.onCreate(); } @Override public void onStart(Intent intent, int startId) { // Æô¶¯·þÎñ // Ö»ÓÐÍš¹ýonStart()·œ·š²Å¿ÉÒÔÈ¡µÃÍš¹ýIntentŽ«µÝ¹ýÀŽµÄÊýŸÝ£¬¶øÈ¥µçºÅÂ뜫͚¹ýŽË·œÊœŽ«µÝ this.outgoingNumber = intent.getStringExtra("outgoingNumber"); // È¡µÃÈ¥µçºÅÂë super.onStart(intent, startId); } @Override public IBinder onBind(Intent intent) { return null; } private class PhoneStateListenerImpl extends PhoneStateListener { // µç»°ŒàÌý @Override public void onCallStateChanged(int state, String incomingNumber) { // žÄ±äºôœÐ׎̬ switch (state) { // ÅжÏ׎̬ case TelephonyManager.CALL_STATE_IDLE: // ûÓвŠÈë»ò²Š³öµç»°²Ù×÷׎̬ break; case TelephonyManager.CALL_STATE_RINGING: // Óе绰œøÈë System.out.println("²ŠÈëµç»°ºÅÂ룺" + incomingNumber + "£¬²ŠÈëʱŒä£º" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date())); // ºóÌšÊä³ö break; case TelephonyManager.CALL_STATE_OFFHOOK: // ʹÓõ绰 System.out.println("²Š³öµç»°ºÅÂ룺" + PhoneService.this.outgoingNumber + "£¬²ŠÈëʱŒä£º" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date())); // ºóÌšÊä³ö break; } } } }