Android 四大组件之BroadcastReceiver

版权所有,禁止匿名转载;禁止商业使用。

1.BroadcastReceiver简介:


BroadcastReceiver 广播接收器,这个组件本质上就是一种全局监听器,用于监听全局广播(Broadcast)消息,因此它可以非常方便的实现系统不同组件之间的通信。


BroadcastReceiver这个监听器与普通的onXxxListener监听器是不同的,onXxxListener是属于应用程序级别的监听器,当程序退出的时候那么这个监听器也就随之结束了。而BroadcastReceiver(配置文件中注册)属于系统级别的监听器,它拥有自己的进程,只要存在与之匹配的Broadcast以intent形式传递过来,那么BroadcastReceiver就会被激活。


与Activity不同的是,当系统通过Intent启动指定的Activity组件时,如果系统没有找到目标Activity组件,这时就会发生程序异常中断,但系统通过Intent激活BroadcastReceiver时,即使没有找到目标BroadcastReceiver时,系统也不会有任何问题


2.创建BroadcastReceiver


2.1 首先需要继承BroadcastReceiver类,重写这个类里面的onReceive()方法,代码如下:


package com.example.administrator.broadcastreceivertest;
 
 import Android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.util.Log;
 import android.widget.Toast;
 
 
 public class MyBroadcastReceiver extends BroadcastReceiver{
     public MyBroadcastReceiver() {
         Log.i("tag","创建构造器...");
     }
 
     @Override
     public void onReceive(Context context, Intent intent) {
         String msg = intent.getStringExtra("msg");
         Toast.makeText(context,msg,Toast.LENGTH_SHORT).show();
     }
 }

当一个BroadcastReceiver被激活之后,系统会为之创建一个BroadcastReceiver实例,并自动触发它的onReceive()方法,onReceive()方法被执行完后,BroadcastReceiver实例就会被销毁。如果BroadcastReceiver的onReceive()方法不能在10s内执行完成,Android会认为该程序无响应,所以不要在onReceive()方法中执行耗时操作,否则会弹出ANR(Application No Response)对话框。


如果在onReceive()方法中需要执行耗时操作,可以考虑使用Intent启动一个Service来完成操作,此时不应该考虑启动一个新的线程去处理耗时操作,因为BroadcastReceiver的生命周期很短,可能子线程还没有结束,BroadcastReceiver就已经退出了。而如果BroadcastReceiver所在的进程结束了,那么该线程就会标记为一个空线程。根据Android内存管理策略,在系统内存紧张时,会根据优先级首先结束优先级低的线程,而空线程优先级无疑是拥有最低的优先级,系统回收后,线程就无法完成相关操作了


2.2 注册BroadcastReceiver


注册BroadcastReceiver的两种方式:


1>使用代码进行指定(动态注册),调用Context类提供的

registerReceiver(BroadcastReceiver receiver,IntentFilter filter);代码如下
      MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
         IntentFilter filter = new IntentFilter(SHOW_MESSAGE);
         registerReceiver(myBroadcastReceiver,filter);

IntentFilter 是根据SHOW_MESSAGE用来匹配Broadcast的,SHOW_MESSAGE是一个自定义的静态字符串常量。


要注意的是,BroadcastReceiver注册的地方,google 官方指出:


Note: If registering a receiver in your  Activity.onResume() implementation, you should unregister it in  Activity.onPause() . (You won't receive intents when paused, and this will cut down on unnecessary system overhead). Do not unregister in  Activity.onSaveInstanceState() , because this won't be called if the user moves back in the history stack.


意思大概是:如果你要在Activity类中的onResume()方法中注册一个receiver,你也应该在Activity类onPause()方法中取消注册。不要在onSaveInstanceState()方法中取消注册,因为如果用户退出当前Activity(从task中移除Activity)时,那么这个BroadcastReceiver也将不能被激活。


特点:当应用程序关闭后,就不再监听。对于我们开发的App来说,越省电就会越受用户的欢迎,所以对于那些没有必要在应用程序退出后仍然进行监听的receiver,在代码中注册是一个不错的选择


2>在AndroidManifest.xml中注册(静态注册),代码如下:

       <receiver android:name=".MyBroadcastReceiver">
             <intent-filter>
                 <action android:name="com.example.administrator.broadcastreceiver.SEND_MESSAGE"/>
             </intent-filter>
         </receiver>

特点:不管应用程序是否处于活动状态,都会进行监听。比如某个应用程序监听内存使用情况,当在手机上安装好之后,不管其处于什么状态都会监听内存状态。


2.3 生命周期


BroadcastReceiver的生命周期很简单,如下图

Android开发,BroadcastReceiver


3.Broadcast介绍


3.1Broadcast被分为两种:


1>Normal Broadcast(普通广播):


Normal Broadcast是完全异步的,可以在同一时刻,被所有接收者接收到(逻辑上),消息传递效率比较高。缺点是接收者不能将结果传给下一个接收者,并且无法阻止Broadcast Intent的传播


2>Ordered Broadcast(有序广播):


Ordered Broadcast的接收者将按照预先声明的优先级次序依次接收Broadcast。如果priority:A>B>C,那么Broadcast先传给A->B->C。


3.2 发送广播的两种方式:


1>sendBroadcast():发送Normal Broadcast


2>sendOrderedBroadcast():发送Ordered Broadcast


对于Ordered Broadcast而言系统会根据接收者声明的优先级别按顺序依次执行接收者,优先收到Broadcast的接收者可以终止Broadcast(调用BroadcastReceiver的abortBroadcast()方法),那么后面的接收者将无法取到Broadcast.


不仅如此,对于Ordered Broadcast而言,优先级别高的接收者,可以通过setResultExtras(Bundle bundle)将结果存到Broadcast中,下一个接收者可以通过Bundle bundle = getResultExtras(true)获取上一个数据


TIP:系统接收短信,发出的Broadcast属于Ordered Broadcast.如果想拦截用户收到短信,可以设置优先级,让自定义的BroadcastReceiver先接收到短信,然后终止broadcast。


4.下面是一个Ordered Broadcast广播例子,代码如下:


MainActivity类:


 package com.example.administrator.broadcastreceivertest;

 

 import android.app.Activity;

 import android.content.Intent;

 import android.os.Bundle;

 import android.view.View;

 

 

 public class MainActivity extends Activity {

 

     private static final String SHOW_MESSAGE = "com.example.administrator.broadcastreceiver.SEND_MESSAGE";

     @Override

     protected void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.activity_main);

     }

 

     public void sendOrderedBroadcast(View view){

         Intent intent = new Intent(SHOW_MESSAGE);

         intent.putExtra("msg","Ordered Broadcast");

         sendOrderedBroadcast(intent,null);

     }

 

 }

MyBroadcastReceiver类


 package com.example.administrator.broadcastreceivertest;

 

 import android.content.BroadcastReceiver;

 import android.content.Context;

 import android.content.Intent;

 import android.util.Log;

 import android.widget.Toast;

 

 

 public class MyBroadcastReceiver extends BroadcastReceiver{

 

     @Override

     public void onReceive(Context context, Intent intent) {

         String msg = intent.getStringExtra("msg");

         Log.i("tag","MyBroadcastReceiver:"+msg);

         Toast.makeText(context,"MyBroadcastReceiver:"+msg,Toast.LENGTH_SHORT).show();

     }

 } 

MyBroadcastReceiver2类


 package com.example.administrator.broadcastreceivertest;

 

 import android.content.BroadcastReceiver;

 import android.content.Context;

 import android.content.Intent;

 import android.util.Log;

 import android.widget.Toast;

 

 

 public class MyBroadcastReceiver2 extends BroadcastReceiver{

 

     @Override

     public void onReceive(Context context, Intent intent) {

         String msg = intent.getStringExtra("msg");

         Log.i("tag","MyBroadcastReceiver2:"+msg);

         Toast.makeText(context,"MyBroadcastReceiver2:"+msg,Toast.LENGTH_LONG).show();

     }

 } 

activity_main.xml


 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"

     android:paddingRight="@dimen/activity_horizontal_margin"

     android:paddingTop="@dimen/activity_vertical_margin"

     android:orientation="vertical"

     android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

 

 

     <Button

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         android:text="发送 Ordered Broadcast "

         android:onClick="sendOrderedBroadcast"/>

 </LinearLayout> 

AndroidManifest.xml


 <?xml version="1.0" encoding="utf-8"?>

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"

     package="com.example.administrator.broadcastreceivertest" >

 

     <application

         android:allowBackup="true"

         android:icon="@drawable/ic_launcher"

         android:label="@string/app_name"

         android:theme="@style/AppTheme" >

         <activity

             android:name=".MainActivity"

             android:label="@string/app_name" >

             <intent-filter>

                 <action android:name="android.intent.action.MAIN" />

 

                 <category android:name="android.intent.category.LAUNCHER" />

             </intent-filter>

         </activity>

 

 

         <receiver android:name=".MyBroadcastReceiver">

             <intent-filter  android:priority="1">

                 <action android:name="com.example.administrator.broadcastreceiver.SEND_MESSAGE"/>

             </intent-filter>

         </receiver>

 

         <receiver android:name=".MyBroadcastReceiver2">

             <intent-filter android:priority="2">

                 <action android:name="com.example.administrator.broadcastreceiver.SEND_MESSAGE"/>

             </intent-filter>

         </receiver>

     </application>

 

 </manifest>

运行结果:


Android开发,BroadcastReceiverAndroid开发,BroadcastReceiver

控制台输出结果:



从运行结果可以看出先是MyBroadcastReceiver2先接收到Broadcast,接着才是MyBroadcastReceiver,因为我在注册时将MyBroadcastReceiver2的优先级设置为2,MyBroadcastReceiver优先级为1。


0 0