什么是Broadcast?

Broadcast,广播,是一种跨进程的消息收发机制。
既然是消息收发,当然存在发送和接收两方。
广播的优点是跨进程。发送方不用关心接收方是谁,只需标注广播的类型,注册对应类型的接收方便可接收。

广播的分类

广播可以按照不同方式进行区分。

根据优先级,分为普通广播和有序广播(之前还有一种粘性广播,在android4.0后被取消,本文不再描述)。

普通广播的接收者,可以看做是并联电路。几乎同时收到广播,没有先后。
有序广播的接收者,按照优先级,从高到低,依次接收,可以看做是串联电路。并且优先级高的接收者,在接收到广播后,可以决定是否继续广播。

根据区域,分为全局广播和本地广播。全局广播是跨进程的,所有进程都能接收到广播。而本地广播,是指仅在同一进程内进行的广播。其它进程接收不到,安全性较高。

广播还可以分为自定义广播和系统广播。
例如,当网络状态发生变化时,android系统会发送action为“android.net.conn.CONNECTIVITY_CHANGE”的系统广播。
用户也可以根据自己的需求,定义自己的广播action。

注册方式

广播接收者跟activity和service类似,都需要注册。但广播的注册分为两种方式,动态注册和静态注册。

动态注册,是在代码中进行注册,因此,仅当程序启动时,才能接收广播。需要注意的是,如果广播的接收者使用动态注册,则需要在必要时,对注册进行注销。

静态注册,则是在Mainfest中进行声明注册。

需要注意的是,本地广播由于只在进程内局部传输,即进程的生命周期内有效,因此只能使用动态注册。
有些系统广播的接收,只能动态注册,静态注册无法接收。例如之前所提到的网络状态监听。

如何发送普通广播

普通的广播发送,需要使用sendBroadcast(Intent)方法。
需要在Intent中指定action名称,可以为自定义,可以为系统。当然,Intent中可以带数据。

Intent intent=new Intent();
intent.setAction("com.breakloop.nfc");
Bundle bundle=new Bundle();
bundle.putString("msg","find card");
intent.putExtras(bundle);
sendBroadcast(intent);

如何发送有序广播

有序广播跟普通广播的发送,唯一不同的是调用方法。
sendOrderedBroadcast(Intent,receiverPermission);
其中第二个参数为String类型,表明接收者所在应用必须拥有对应的权限(Permission,可以自定义)。例如指定“android.permission.INTERNET”。
若无指定,可以设置为null.

Intent intent=new Intent();
intent.setAction("com.breakloop.nfc");
Bundle bundle=new Bundle();
bundle.putString("msg","find card");
intent.putExtras(bundle);
sendOrderedBroadcast(intent,null);

如何发送本地广播

本地广播的发送,以及接收者的注册/注销,都是由LocalBroadcastManager来控制的。

(a)发送本地广播

Intent intent=new Intent();
intent.setAction("com.breakloop.nfc");
Bundle bundle=new Bundle();
bundle.putString("msg","find card");
intent.putExtras(bundle);

LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);
localBroadcastManager.sendBroadcast(intent);

(b)注册本地广播接收器

MyReceiver myReceiver=new MyReceiver();

IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.breakloop.nfc");

localBroadcastManager.registerReceiver(myReceiver,intentFilter);

其中MyReceiver 为自定义的广播接收器。

(c)注销本地广播接收器

localBroadcastManager.unregisterReceiver(myReceiver);

如何创建广播接收器

自定义广播接收器,实现BroadcastReceiver接口。该接口只有一个方法
public void onReceive(Context context, Intent intent)

例如

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle=intent.getExtras();
        if(bundle==null){
            return;
        }

        Intent newIntent;
        if (intent.getAction().equalsIgnoreCase("com.breakloop.nfc")){
            newIntent=new Intent(context,MainActivity.class);
        }else {
            newIntent=new Intent(context,OtherActivity.class);
        }

        newIntent.putExtras(bundle);
        context.startActivity(newIntent);
    }
}

如何动态注册广播接收器

MyReceiver myReceiver=new MyReceiver();

IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.breakloop.nfc");
intentFilter.setPriority(Integer.MAX_VALUE);//用于定义优先级,Optional

registerReceiver(myReceiver,intentFilter);

如何注销动态广播接收器

unregisterReceiver(myReceiver);

注:如果仅让处于栈顶端的Activity接收到广播,可以在onResume中注册广播接收器,在onPause中注销。

如何静态注册广播接收器

需要在Mainfest的Application内,注册接收器类名,以及接受的Intentfilter action。
当然,一个接收器可以接收多个广播。例如。

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="com.breakloop.nfc.A"/>
        <action android:name="com.breakloop.nfc.B"/>
    </intent-filter>
</receiver>

如何定义有序广播的优先级

<receiver android:name=".MyReceiver">
    <intent-filter android:priority="1000">
        <action android:name="com.breakloop.nfc.A"/>
        <action android:name="com.breakloop.nfc.B"/>
    </intent-filter>
</receiver>

需要在intent-filter中添加android:priority来指定优先级,其中1000为优先级值。该值越大,优先级越高。官方定义优先级最大最小分别为1000和-1000。
但Intentfilter的priority为Integer类型,可以设置为Integer.MAX和Integer.MIN。

如何在接收有序广播后,阻断广播的传播。

在OnReceive方法中调用abortBroadcast(),即可停止广播的继续进行。