您的位置:首页 > 移动开发 > Android开发

Android复习之BroadCastReceiver

2016-10-20 23:29 97 查看

是什么

BroadCastReceiver是四大组件之一,相当于一个全局的监听器,用于监听系统全局的广播。

怎么样

由于BroadCastReceiver是全局监听器,因此它可以方便的实现系统中不同组件之间的通信。

怎么用

实现步骤分三步

创建BroadCastReceiver

创建需要启动BroadCastReceiver的Intent

调用Context的sendBroadCast或sendOrderBroadCast方法启动指定的receiver

receiver需要继承BroadCastReceiver并实现onReceive方法,当程序发出一个BroadCast的Intent之后所有匹配了改Intent的BroadCastreceover都有可能会被启动

与Activity和Service不同的是BroadCastReceiver生命周期比较短,本质是一个系统级全局的监听器,专门负责监听个程序所发出的BroadCast

实现了BroadCastReceive就要有与只匹配的Intent

两种匹配intent方式

在代码中动态设置,通过intentFilter设置Action

在AndroidMainifest中的receiver标签中设置Action

值得注意的是:

执行完onReceiver后实例会被销毁,生命周期短

发送广播后如果没有与之匹配的receiver,程序不会报错,这与Activity和Service不同

不能在onReceiver方法中做耗时操作,10秒内onReceive方法没有执行完成会被认为程序无响应,因此耗时操作应该在Service中开启线程来执行

两种发送广播的方式

sendBroadCast()普通广播

sendOrderBroadCast()有序广播

有序广播会根据优先级别按顺序执行接收者,优先接到的可通过abortBroadCast来终止广播,也可以通过setResultExtra()来修改接收到的值并传递,下一个广播在通过getResultExtra()来获取。

两种注册方式

动态注册,广播会跟随程序的生命周期,在Activity或service中注册,但是必须到onDestroy中销毁,不然会报错

静态注册,常驻型,即使应用关闭,也能够接收广播

代码演示

xml里面两个按钮,一个动态注册,一个静态注册



按照前面说的第一步,先创建一个类
TestReceiver
继承
BroadcastReceiver
,该类是一个抽象类,需要实现里面的抽象方法
onReceive(Context context, Intent intent)


public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = intent.getStringExtra("sky");
Log.d("TestReceiver", "接收到的值" + sky);

}
}


这里面的
Intent
就是接收传过来的值

第二步,创建匹配该
broadCastReceiver
Intent
,首先要给
broadCastReceiver
设置一个Action,然后再通过给Intent设置Action,如果Intent的Action
broadCastReceiver
Action匹配,也就是一样,则
broadCastReceiver
将会被系统启动,接收到Intent传过来的消息。首先注册广播,由上面可知注册有动态注册和静态注册,

动态注册代码

receiver = new TestReceiver();
registerReceiver(receiver, new IntentFilter(ACTION));


由于动态注册广播会跟随程序的生命周期,所以注册时实例化应该声明为全局变量,以便在onDestroy中注销,否则会报错!

通过registerReceiver方法来动态注册广播,参数1是被注册的广播,参数2是IntentFilter,设置broadCastReceiver的Action,

2. 动态注册代码

<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>


在AndroidMainifest中注册,这是常驻性注册,即使应用被关闭,接收到匹配的Action,广播也能被启动,也是通过Iintent-filter标签来设置Action。

这两种注册方式,根据需求进行选择,选择动态注册,务必记得手动注销

@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}


第三步,发送广播,注册好了广播,就可以使用了,在按钮的点击事件中添加如下代码

/**
* 匹配Intent,与这个Action相同的接收者都会接收到。
*/
Intent intent = new Intent();
intent.setAction(ACTION);
intent.putExtra("sky", "I appreciate the man who are goood at Android");
sendBroadcast(intent);


这里的ACTION与注册广播时的ACTION要一样,否则匹配失败,无法接收

public static final String ACTION = "com.cd.broadcastreceiver";


这个ACTION字符串可以是任意的,但是为了看起来规范,选择包名的形式。

点击按钮看到如下输出



说明广播是接收到了。

这里是一个接收者一个发送者,而且匹配的ACTION一致,如果有多个接收者匹配了同一个发送者的ACTION会不会都收到,或者多个接收者之间有没有相互的影响呢?

在上面的基础上添加另外两个接收者
TestReceiver2
TestReceiver3
,然后我选择静态注册

  <!--<receiver android:name=".TestReceiver"/>-->
<receiver android:name=".TestReceiver"> <intent-filter> <action android:name="com.cd.broadcastreceiver"></action> </intent-filter> </receiver>
<receiver android:name=".TestReceiver2">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver3">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>


这里三个接收者都是设置的相同的ACTION.

发送代码不变,点击按钮输出如下



三个都接收到了,而且输出顺序是按照AndroidMainifest注册顺序输出的,不确定这两者之间有没有关系,知道的麻烦告诉我一声。

接着我在第一个广播的onReceiver 方法中添加了
abortBroadcast();
终止广播。



再次运行,输出如下



还是接收到了,表明接收者不能终止广播,注意到在
abortBroadcast
的地方报了个错,这个先不管,

那么如何终止广播或者在广播传播的过程中修改广播内容呢?可以使用有序广播

有序广播每次只发送到优先级高的那里,然后由优先级高的依次往优先级低的发送,优先级高的可以决定终止或继续传播这个广播。

修改之前三个接收者的代码如下

第一个广播
TestReceiver


public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = intent.getStringExtra("sky");
Log.d("TestReceiver", "接收到的值" + sky);
Bundle bundle=new Bundle();
bundle.putString("message",sky+"from TestReceiver");
setResultExtras(bundle);
}
}


第二个广播
TestReceiver2


public class TestReceiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = getResultExtras(true).getString("sky");
Log.d("TestReceiver2", "接收到的值" + sky);
Bundle bundle=new Bundle();
bundle.putString("message",sky+"message from TestReceiver2");
setResultExtras(bundle);
}
}


第三个广播
TestReceiver3


public class TestReceiver3 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = getResultExtras(true).getString("sky");
Log.d("TestReceiver3", "接收到的值" + sky);

}
}


通过
setResultExtras
写入数据,
getResultExtras
获取数据

AndroidMainifest修改如下

<!--<receiver android:name=".TestReceiver"/>-->
<receiver android:name=".TestReceiver"
>
<intent-filter android:priority="10">
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver2">
<intent-filter android:priority="9">
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver3">
<intent-filter android:priority="8">
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>


注意到,在intent-filter标签下,添加了
android:priority
属性,这是是设置广播的优先级,取值范围是-1000~1000,值越大,优先级越高,如果没有设置优先级会报这个错

BroadcastReceiver trying to return result during a non-ordered broadcast


而且只有第一个声明的能接收到,后面的无法接收。

修改发送广播的代码

Intent intent1 = new Intent();
intent1.setAction(ACTION);
intent1.putExtra("sky","register in AndroidMainifest");
sendOrderedBroadcast(intent1,null);


sendBroadcast
改为
sendOrderedBroadcast
,这里多了一个权限参数,null表示不用权限,想了解权限可看这篇文章Android声明和使用权限

修改完,点击按钮输出为



由图可以看到,接收顺序是按照优先级来执行的,以及传递的值也是依次接收到了,【这里有个疑问,在输出的最后一行,第一个广播又输出了一次,这个很不可思议,不是广播在onReceive方法执行完后,实例就被摧毁了么,为什么会执行两次呢?如果有人看到这篇文章,并且知道造成的原因,麻烦告诉我一下,谢谢】

现在再次在TestReceiver的onReceiver中调用
abortBroadcast();


输出如下



可以看到,优先级高的接收到了广播,后面优先级低的就被终止了,而且没有报之前那个错了。所以
abortBroadcast
要在有序广播中使用。

参考:

http://www.jianshu.com/p/903e08cba4b6
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息