Android - BroadcastReceiver

在  Android - Intent与IntentFilter  一文的开头,我们提到,一个Intent是对将要被执行的一个操作的一种抽象的描述,结合Context类中定义的下列几个方法 ——

[java]  view plain  copy
  1. public abstract void startActivity(Intent intent);  
  2. public abstract void sendBroadcast(Intent intent);  
  3. public abstract ComponentName startService(Intent service);  
  4. public abstract boolean bindService(Intent service, ServiceConnection conn, int flags);   

Intent被用作一种组件之间进行通信的媒介。
public abstract void startActivity(Intent intent)方法是根据指定的intent开启对应的Activity,
public abstract ComponentName startService(Intent service)方法是根据指定的intent开启对应的Service,
那么, public abstract void sendBroadcast(Intent intent)方法呢?

一般来说,Intent主要是用作Activity和Service之间通信的媒介,在Activity(Service)中通过Intent开启一个Service(Activity)。
那么,如果我们需要在应用中根据一个Intent来做某些具体的操作(不一定是开启一个Activity或Service)呢?在Context类中可没有什么方法能满足我们的需要,这种情况下,就可以考虑使用广播接收者了。上文中提到的public abstract void sendBroadcast(Intent intent)方法就是用于发送intent的,广播接收者则用于处理intent。

正如startActivity(Intent intent)和startService(Intent service)这两个方法都需要它们所传递的intent先通过IntentFilter的过滤才能开启对应的Activity和Service一样,广播接收者并不会处理所有通过sendBroadcast(Intent intent)方法发送来的intent,它同样需要先声明自己能处理哪些intent。
本文也按照 创建广播接收者--订阅感兴趣的广播intent--发送广播intent--处理广播intent 的顺序来写。

一、创建广播接收者
创建一个广播接收者只需要继承BroadcastReceiver,并重写onReceive()方法,如:
[java]  view plain  copy
  1. public class myBroadcastReceiver  extends BroadcastReceiver{  
  2.     @Override  
  3.     public void onReceive(Context context, Intent intent) {  
  4.         // TODO Auto-generated method stub  
  5.         ... ...  
  6.     }     
  7. }  
二、订阅感兴趣的广播Intent
订阅的方法有两种:                      
第一种:使用代码进行订阅(动态订阅): 
[java]  view plain  copy
  1. public void registerStorageChangeReceiver() {  
  2.     IntentFilter filter = new IntentFilter();  
  3.     filter.addAction(Intent.ACTION_MEDIA_SHARED);  
  4.     filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);  
  5.     filter.addAction(UPDATE_LISTVIEW_STRING);  
  6.     filter.addDataScheme("file");  
  7.     storageChangeReceiver = new StorageChangeReceiver();  
  8.     getActivity().registerReceiver(storageChangeReceiver, filter);  
  9. }  
第二种:在AndroidManifest.xml文件中的<application>节点里进行订阅( 静态订阅):
[java]  view plain  copy
  1. <receiver android:name=".autotask.AutoTaskReceiver">  
  2.     <intent-filter>  
  3.         <action android:name="android.intent.action.BOOT_COMPLETED" />  
  4.     </intent-filter>  
  5.     <intent-filter>  
  6.         <action android:name="android.intent.action.DATE_CHANGED" />  
  7.     </intent-filter>  
  8. </receiver>  
两种订阅方式的区别:

静态订阅广播又叫常驻型广播,当应用程序关闭了,如果有广播intent到来,广播接收者同样能接收到。

动态订阅广播又叫非常驻型广播,当应用程序结束了,广播接收者也就被销毁了。


三、发送广播

发送广播的方法定义在Context类中,主要有:

[java]  view plain  copy
  1. public abstract void sendBroadcast(Intent intent);  
  2. public abstract void sendBroadcast(Intent intent, String receiverPermission);     
  3.   
  4. public abstract void sendOrderedBroadcast(Intent intent, String receiverPermission);  
  5. public abstract void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,  
  6.             Handler scheduler, int initialCode, String initialData, Bundle initialExtras);  
sendBroadcast()用来发送“普通广播(Normal broadcasts)”
sendOrderedBroadcast()用来发送“有序广播(Ordered broadcasts)”。
    
普通广播(Normal broadcasts)是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。              
有序广播(Ordered broadcasts)则按照接收者声明的优先级别被依次接收。如:A的级别高于B的级别高于C的级别,那么,广播先传给A,再传给B,最后传给C 。  优先级别声明在 intent-filter 元素的 android:priority 属性中,数值越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置。     
有序广播的接收者可以终止广播Intent的传播(BroadcastReceiver.abortBroadcast()),广播Intent的传播一旦终止,后面的接收者就无法接收到广播。         
另外,有序广播的接收者可以通过setResultExtras(Bundle)方法将数据存放进结果对象,然后将数据传递给下一个接收者,下一个接收者通过代码:Bundle bundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。       


四、处理广播Intent

每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法,         

onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。        

当onReceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)对话框。         

如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。这里不能使用子线程来解决,因为 BroadcastReceiver 的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。         

BroadcastReceiver一旦结束,此时BroadcastReceiver所在的进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。

Android将进程分为6个等级,它们按优先级顺序由高到低依次是:

1.前台进程( FOREGROUND_APP)

2.可视进程(VISIBLE_APP )

3. 次要服务进程(SECONDARY_SERVER )

4.后台进程 (HIDDEN_APP)

5.内容供应节点(CONTENT_PROVIDER)

6.空进程(EMPTY_APP)


所以,Intent是组件(主要是Activity和Service)之间进行通信的媒介。广播接收者通过订阅并处理Intent则是组件(主要是Activity和Service)间进行通信的一种方式。



... ... (未完待续)

你可能感兴趣的:(android)