广播机制简介
Adroid中的广播主要分为两种类型:标准广播和有序广播。
标准广播:
标准广播是一种完全异步执行的广播,在广播发出以后,所有的广播接收器几乎都会在同一时刻接收到这条广播信息,因此它们之间没有图呢he先后顺序可言,这种广播效率会比较高,但也以为着它是无法被截断的
有序广播
有序广播是一种同步执行的广播,在广播发出以后,同一时刻只会有一个广播接收器能接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就优先接收到广播消息,并且前面的广播接收器可以截断正在传递的广播,后面的广播接收器就不能接收到广播消息了。
接收系统广播
Android内置了很多系统级别的广播,我们可以在程序中监听这些广播来得到系统的状态信息,比如,手机开机后系统会发送一条广播,电池没电了系统也会发送一条广播。如果想接收到这些广播就需要使用广播接收器。
注册方式
广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广播接收器就能接收到该广播,并在内部处理相应的逻辑。注册广播方式一般有两种,第一种实在代码中注册,第二种实在AndroidManifest.xml中注册,前者成为动态注册,后者成为静态注册
下面举几个例子
-
动态注册监听网络变化,新建项目BroadcastTest1
如何建一个广播接收器?只需建一个类继承BroadcastReceiver并重写父类的onReceiver方法就行了,当有广播到来时onReceiver方法就会得到执行
class NetWorkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "网络发生了变化", Toast.LENGTH_SHORT).show();
}
}
这个类可以写在Activity的内部,也可以另外建一个类
- 监听网络状态变化
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetWorkChangeReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
receiver = new NetWorkChangeReceiver();
registerReceiver(receiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
class NetWorkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "网络发生了变化", Toast.LENGTH_SHORT).show();
}
}
}
当系统网络状态发生变化的时候,系统就会发出一条值为android.net.conn.CONNECTIVITY_CHANGE的广播,所以我们在IntentFilter中添加相应的action,然后调用registReceiver方法进行注册,传入NetWorkChangeReceiver和IntentFilter的实例,这样就实现了监听网络变化的功能。最后记得动态注册的广播接收器一定要取消才行,即在onDestroy中通过调用unregisterReceiver方法来实现
- 监听网络是否可用
我们创建一个SecondActivity,并创建一个NetWorkChangeReceiver继承BroadcastReceiver并重写onReceive方法
public class SecondActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetWorkChangeReceiver netWorkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
intentFilter=new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
netWorkChangeReceiver=new NetWorkChangeReceiver();
registerReceiver(netWorkChangeReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(netWorkChangeReceiver);
}
class NetWorkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//getSystemService根据名字获取一个系统级别的服务类
NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
if(networkInfo!=null&&networkInfo.isAvailable()){
Toast.makeText(context,"网络可用",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context,"网络不可用",Toast.LENGTH_SHORT).show();
}
}
}
}
在onReceive方法中首先通过getSystemService获得ConnectivityManager的实例,这是四专门用于管理网络连接的,然后调用它的getActiveNetworkInfo方法获得一个NetworkInfo的实例,最后调用NetworkInfo的isAvailable方法判断当前是否有网络,通过Toast提示。
这里访问系统的网络状态是要声明权限的
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
我们点击NETWORK_CHANGE_DETAILS按钮,启动SecondACtivity,打开或关闭数据服务就能看到Toast提示
-
静态注册实现开机启动监听(系统开机后会发送一条广播)
动态注册的广播接收器可以自由地注册和注销,很灵活,但是它有个缺点就是必须 要把程序启动之后才能实现监听,因为注册逻辑是卸载onCreate方法中的。
使用静态注册的方式能让程序在未启动的状态下实现监听广播。下面看怎么使用
-
新建一个广播接收器名为BootCompletReceiver并将Exported和Enabled属性勾选。Exported属性表示是否允许这个广播接收器接收本程序以外的广播,Enabled属性表示是否启用这个广播接收器
public class BootCompletReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"开机完成",Toast.LENGTH_SHORT).show();
}
}
- 静态注册的广播接收器一定要在AndroidManifest.xml文件中注册才能使用,但由于我们是使用AS自带的快捷方式创建的广播接收器,所以它自动帮我们将这一步完成了
<receiver
android:name=".BootCompletReceiver"
android:enabled="true"
android:exported="true">
</receiver>
- 所有的静态广播接收器都要在<receiver>标签内进行注册,name用来制定是注册哪一个广播接收器,enabled和exported是根据我们刚才勾选的状态自动生成的。
由于系统启动后会发送一条值为android.intent.action.BOOT_COMPLETED的广播,所以我们要在<intent-filter>标签中添加相应的action
<receiver
android:name=".BootCompletReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
- 添加相应的权限,监听系统开机广播是需要声明权限的
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
这样就能实现开机程序监听开机广播了
-
发送自定义广播
前面介绍了广播分为两种:标准广播和有序广播
发送自定义标准广播,新建MyBroadcastReceiver项目
- 我们新建一个自定义的广播接收器
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"我自定义的广播",Toast.LENGTH_SHORT).show();
}
}
- 在布局里面添加一个Button,点击这个Button就会发送我们自己定义的广播
public void sendbroadcast(View view) {
Intent intent = new Intent("com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver");
sendBroadcast(intent);
}
Intent中传入的是一条Action值,然后调用sendBroadcast方法将intent传进去,当然现在还是不能监听广播的,我们还需要在清单文件中配置一下
- 修改AndroidManifest.xml
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
</intent-filter>
</receiver>
这样我们的点击Button就会发出一条我们自定义的广播并且能接收到这条广播了
发送自定义的有序广播
- 发送有序广播非常简单,只需要将sendBroadcast改成sendOrderedBroadcast并传入两个参数
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void sendbroadcast(View view) {
Intent intent = new Intent("com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver");
//sendBroadcast(intent);
sendOrderedBroadcast(intent, null);
}
}
第一个参数是Intent不用解释,另一个参数是一个与权限相关的字符串官方解释是:String naming a permissions that a receiver must hold in order to receive your broadcast. If null, no permission is required.一般情况下传入null就可以了,除特殊情况。
- 成功发送有序广播后我们再试图去别的程序里面截断这条广播,使发出这条广播的程序无法接收到这条广播
在上面动态注册监听网络变化BroadcastTest1项目里面创建一个AnotherBroadcastReceiver
public class AnotherBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"在Broadcasttest1中接收到了MyBroadcastReceiver发出的广播",Toast.LENGTH_SHORT).show();
abortBroadcast();//截断这条广播
}
}
截断广播非常简单,只需要在BroadcastReceiver中调用abortBroadcast()方法就行了
- 然后修改BroadcastTest1项目中的AndroidManifest.xml文件
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
</intent-filter>
</receiver>
- 要想截断这条广播那么我们就必须保证BroadcastTest1程序优先于MyBroadcastReceiver程序接收到MyBroadcastReceiver程序发送的广播,并截断这样MyBroadcastReceiver程序就不会接收到它自己发送的广播了。怎样做呢?其实只需要设置一个优先级就可以了,添加android:priority="100",设置成一百就可以了
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter
android:priority="1000">
<action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
</intent-filter>
</receiver>
这样BroadcastTest1程序就能接收到MyBroadcastReceiver程序发送过来的广播了,并且能截断它。
-
使用本地广播
上面讲的发送和接收的都属于全局广播,即发出的广播可以被其他任何应用程序接收到,并且也可以接受来自其他程序的广播,这样就不够安全,为了解决这个安全问题,Android引入了一套本地的广播机制,使用这个机制程序发出的广播只能在程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样安全性问题就不存在了。
主要是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法,看例子:
package com.example.houchongmu.mybroadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class LocalBroadcastActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalBroadcast localBroadcast;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_local_broadcast);
intentFilter=new IntentFilter();
localBroadcast=new LocalBroadcast();
localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取LocalBroadcastManager的实例
intentFilter.addAction("com.example.localbroadcast");
localBroadcastManager.registerReceiver(localBroadcast,intentFilter);
}
public void send_localbroadcast(View view){
Intent intent=new Intent("com.example.localbroadcast");
localBroadcastManager.sendBroadcast(intent);
}
class LocalBroadcast extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"接收到本地广播",Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(localBroadcast);
}
}
上面的代码很容易理解就不过多解释了
关于广播机制就暂时讲到这里,以后学习到新的知识再进行补充。