Android学习笔记2-1--组件3--Reciver

来源:互联网 发布:淘宝活动时间表 编辑:程序博客网 时间:2024/06/11 22:24

组件简介

广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件,即使本应用程序的其他组件都没有运行也没关系。很多广播是源自于系统代码的──比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。
广播接收器没有用户界面。然而它们可以启动一个activity来响应它们收到的信息或用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

BroadcastReceiver用于异步接收广播Intent。主要有两大类,用于接收广播的:

正常广播Normal broadcasts(用Context.sendBroadcast()发送)是完全异步的。它们都运行在一个未定义的顺序(通常是在同一时间)。这样会更有效但意味着receiver不能包含所要使用的结果或中止的API。
有序广播Ordered broadcasts(用Context.sendOrderedBroadcast()发送。有序就是每个receiver执行后可以传播到下一个receiver,也可以完全中止传播——不传播给其他receiver。 而receiver运行的顺序可以通过matched intent-filter里面的android:priority来控制,当priority优先级相同的时候,Receiver以任意的顺序运行。

一个BroadcastReceiver对象只有在被调用onReceive(Context, Intent)的才有效的,当从该函数返回后,该对象就无效了而结束生命周期。

因此从这个特征可以看出,在所调用的onReceive(Context, Intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作请用service来完成。因为当得到其他异步操作所返回的结果时,BroadcastReceiver可能已经无效。

组件定义

组件声明

注册方式有两种,两种方式都需要IntentFIlter:

一种是静态注册,就是在AndroidManifest.xml文件中定义,注册的广播接收器必须要继承BroadcastReceiver。

< receiver android:enabled=["true" | "false"] # 广播接收器是否能被系统实例化          android:exported=["true" | "false"] # 广播接收器能否接收来自应用程序之外的消息。如果设为“\false则本接收器只能接收本应用程序或用户ID相同程序的组件的消息。          android:icon="drawable resource"           android:label="string resource"           android:name="string"           android:permission="string" # 发送方要发送消息给广播接收器所必需的权限名称          android:process="string" # 运行广播接收器的进程名称。 通常,应用程序的所有组件都运行在创建时的默认进程中。 该进程的名称与程序包名相同。                                    # 如果本属性值的名称以冒号(':')开头,则必要时会新建一个属于该程序私有的进程,广播接收器将运行于该新进程中。                                    # 如果进程名称以小写字母开头,则广播接收器将运行于一个以此名字命名的全局进程中,并赋予相应的访问权限。          />            <intent-filter>                  <action android:name="android.intent.action.BATTERY_LOW" />  # 使用过滤器,接收指定action广播          </intent-filter>  < /receiver > 

一种是动态注册,是在程序中使用Context.registerReceiver注册,注册的广播接收器相当于一个匿名类。

在Context中通过registerReceiver注册,通过unregisterReceiver注销。在registerReceiver第二个参数中通过IntentFilter设置消息过滤类型。

组件方法

当发送的广播被接收器监听到后,会调用它的onReceive()方法,并将包含消息的Intent对象传给它。onReceive中代码的执行时间不要超过5s,否则Android会弹出超时dialog。

public void onReceive(Context context, Intent intent);

下面给出动态注册的接收来电的广播处理的CallReceiver的代码,可通过PhoneStateListener的onCallStateChanged来监听状态的变化:

# 监听通话状态需要加上权限:<uses-permission android:name="android.permission.READ_PHONE_STATE"/>public class CallReceiver extends BroadcastReceiver {         private Context m_context;         @Override         public void onReceive(Context context, Intent intent) {                 m_context = context;                 TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);                 teleManager.listen(new PhoneStateListener(){                         @Override                         public void onCallStateChanged(int state, String incomingNumber) {                                 switch(state){                                 case TelephonyManager.CALL_STATE_RINGING: //响铃                                         Toast.makeText(m_context, "Ringing: " + incomingNumber, Toast.LENGTH_LONG) .show();                                         break;                                 case TelephonyManager.CALL_STATE_OFFHOOK: //接听                                         Toast.makeText(m_context, "OffHook: " + incomingNumber, Toast.LENGTH_LONG) .show();                                         break;                                 case TelephonyManager.CALL_STATE_IDLE: //挂断                                         Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG) .show();                                         break;                                 }                         }}, PhoneStateListener.LISTEN_CALL_STATE);          }}# 下面代码是错误的,因为在运行时,发现除了响铃时可以获取来电号码,接听和挂断都不能成功获取的,显示为nullpublic class CallReceiver extends BroadcastReceiver {        @Override         public void onReceive(Context context, Intent intent) {                 TelephonyManager teleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);                 switch(teleManager.getCallState()){                 case TelephonyManager.CALL_STATE_RINGING: //响铃                         Toast.makeText(context, "Ringing: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show();                         break;                 case TelephonyManager.CALL_STATE_OFFHOOK: //接听                         Toast.makeText(context, "OffHook: " + intent.getStringExtra("incoming_number"), Toast.LENGTH_LONG).show();                         break;                 case TelephonyManager.CALL_STATE_IDLE: //挂断                         Toast.makeText(m_context, "Idle: " + incomingNumber, Toast.LENGTH_LONG).show();                         break;                 }         }}

组件调用

发送时把要发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用sendOrderBroadcast()或sendOrderedBroadcast()等方法,把该Intent对象以广播方式发送出去。

1)sendBroadcast:无序的发送广播机制。理论上所有的接受者同时获得该intent的消息,接受者之间不存在先后顺序且不能截断/修改intent的数据。应用普遍使用的就是该方式。
2)sendOrderedBroadcast:有序的发送广播的机制。所有接受者都可以设置priority,按照priority的大小顺序进行传递,上一个优先级的接受者,可以截断和修改intent里面的数据。 同时也可以设置一个最后接收者(总是在最后一个接收到这个intent,用来做一些特定的功能)。
3)sendStickyBroadcast: 粘性的发送广播机制。所谓的粘性是指这个intent没有周期限制。一般的intent只能发送给当前已经注册了这个监听的receiver,一旦发送完毕就会失去作用周期。而粘性广播没有这个限制,即便后来注册的intent也可以收到这个广播。需要注意的一点是这种发送方式不会导致ANR,因为它没有发送时间的限制。
4) sendBroadcastAsUser:用户的发送广播机制。android4.2之后加入了多用户,UserHandle.ALL/UserHandle.CURRENT /UserHandle.CURRENT_OR_SELF/UserHandle.OWNER。这就造就了它用来区分不同的用户。

请注意:BroadcastReceiver运行在主线程中。BroadcastReceiver并不是一个新的线程,也不是新的进程。也就是说,若您需要在BroadcastReceiver中执行较为耗时的操作(如播放音乐、执行网络请求等),需要在BroadcastReceiver中创建一个新的线程。这可以防止ANR的发生,同时主线程可以执行正常的UI操作。

原创粉丝点击