一、简介
Android中的每个app都可以对自己感兴趣的广播进行注册,这样程序就只会接收到自己关心的广播内容,这些广播可能是来自系统的,也可能来自其他应用程序。发送广播要用到 Intent,接收广播要用到 BroadcastReceiver
二、Android中广播的类型
1、标准广播
标准广播是一种 异步执行 的广播,在广播发出之后,所有BroadcastReceiver几乎会在同一时刻接收到这条广播消息,因此它们之间没有先后顺序可言。
优点:效率高 缺点:无法截断
2、有序广播
有序广播是一种 同步执行 的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver接收到这条消息,当这个BroadcastReceiver执行完毕之后,广播才会继续传递。
因此这种方式下,BroadcastReceiver是有先后顺序的,优先级高的BroadcastReceiver就能先收到广播消息,并且前面的BroadcastReceiver还可以截断广播,让后面的接收器无法收到。
三、如何接收广播
Android中有很多系统级别的广播,比如手机开机之后发出一条广播、电池电量变化会发出一条广播,我们可以在app中通过监听这些广播来得到系统的状态信息,要想接收这些广播,就得使用 广播接收器。
广播接收器可以自由的对自己感兴趣的广播进行注册,当有相应的广播发出时,广播接收器就能收到该广播,并在内部处理。注册广播有动态注册和静态注册,前者是在代码中注册,后者是在AndroidManifest.xml中注册
1、动态注册
下面是一个通过动态注册广播,来监听网络变化的程序:
首先,添加获取网络状态的权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
然后编写代码:
public class CastActivity extends AppCompatActivity {
private IntentFilter mIntentFilter;
private NetworkChangeReceiver broadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cast);
//创建IntentFilter
mIntentFilter = new IntentFilter();
//添加行为
mIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
//创建一个BroadcastReceiver
broadcastReceiver = new NetworkChangeReceiver();
//用IntentFilter注册BroadcastReceiver
registerReceiver(broadcastReceiver,mIntentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//解除注册BroadcastReceiver
unregisterReceiver(broadcastReceiver);
}
/*
* 自定义的广播接收器类
* */
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//利用 ConnectivityManager 和 NetworkInfo 去监听网络状态
ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()){
Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();
}
}
}
}
上面的IntentFilter是用来注册BroadcastReceiver的
它添加了一个action (android.net.conn.CONNECTIVITY_CHANGE),IntentFilter的作用是可以过滤Intent,利用这个IntetFilter注册了我们的BroadcastReceiver之后,我们的BroadcastReceiver就具备了接收"android.net.conn.CONNECTIVITY_CHAGE"这个系统广播的能力。
附:Intent和IntentFilter?
Android中提供了 Intent 机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
Intent本身是一个被动的数据结构,保存着要执行操作的抽象描述。例如,你有一个活动,需要打开邮件客户端并通过 Android 设备来发送邮件。为了这个目的,你的活动需要发送一个带有合适选择器的 ACTION_SEND 到 Android 意图处理。指定的选择器给定合适的界面来让用户决定如何发送他的邮件数据,这将用到IntentFilter。
Intent作用的表现形式为:
- 通过Context.startActivity()orActivity.startActivityForResult() 启动一个Activity;
- 通过 Context.startService() 启动一个服务,或者通过Context.bindService() 和后台服务交互;
- 通过广播方法(比如 Context.sendBroadcast(),Context.sendOrderedBroadcast()) 发给broadcast receivers
Android 操作系统使用 IntentFilter 来指定一系列活动、服务和广播接收器处理意图,需要借助于意图所指定的动作、类别、数据模式。
2、静态注册
动态注册的广播接收器能自由的注册和注销,比较灵活,但是它的缺点是,必须在程序启动之后才能接收到广播,因为逻辑是在onCreate()方法中的。要想在程序未启动的时候收到广播,就需要使用 静态注册 的方式。
下面我们实现一个开机广播。
首先,定义一个广播接收器类
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"boot compelete!",Toast.LENGTH_SHORT).show();
}
}
然后在AndroidManifest.xml文件中的<application>标签内注册该receiver
<receiver
android:name=".BootCompleteReceiver"
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"/>
然后这样的话,下次重启手机之后,就会提醒"boot completed!"。
3、自定义广播
上面的例子都是定义一个广播接收器去接收系统广播,那么如何去发送自定义广播呢?
发送标准广播
首先,定义一个广播接收器
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String castMsg = intent.getStringExtra("broadcast_tag");
Toast.makeText(context,"received broadcast: " + castMsg,Toast.LENGTH_SHORT).show();
}
}
然后,在AndroidManifest.xml文件中注册这个receiver
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.yy.MY_BROADCAST" />
</intent-filter>
</receiver>
最后,在一个Activity中写出发送广播的逻辑
broadcastBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.yy.MY_BROADCAST");
intent.putExtra("broadcast_tag","this is a broadcast");
sendBroadcast(intent);
}
});
最后,点击按钮就会发送广播消息"this is a broadcast",并且被MyBroadcastReceiver中的onReceive()方法接收。
[注] 这种方式发送的广播会被其他应用程序接收到,只要其他应用程序的<application>闭包内的<receiver>的action也是com.example.yy.MY_BROADCAST。
发送有序广播
首先,在<receiver>闭包的<intent-filter>中可以设置接收器的优先级:
<intent-filter android:priority="100">
<action android:name="com.example.yy.MY_BROADCAST" />
</intent-filter>
这样优先级更高的BroadcastReceiver会先收到广播消息
其次,在MyBroadcastReceiver中的onReceiver()方法中可以调用abortBroadcast()方法,可以将广播消息截断,让后面的接收器无法接收到广播消息。
4、本地广播
前面的广播都是系统全局广播,这样的广播能被其他程序收到,这样安全性就不好。为了解决安全性问题,就得用到本地广播,主要是用 LocalBroadcastManager 来管理。下面的例子是LocalBroadcastManager配合动态注册的方式实现的本地广播。
public class LocalCastActivity extends AppCompatActivity {
private IntentFilter mIntentFilter;
private LocalReceiver mLocalReceiver;
private LocalBroadcastManager mLocalBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_local_cast);
//创建LocalBroadcastManager
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
Button button = findViewById(R.id.broadcast_btn2);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.yy.LOCAL_BROADCAST");
//发送一个本地广播
mLocalBroadcastManager.sendBroadcast(intent);
}
});
//创建IntentFilter
mIntentFilter = new IntentFilter();
mIntentFilter.addAction("com.example.yy.LOCAL_BROADCAST");
//创建LocalReceiver
mLocalReceiver = new LocalReceiver();
//利用BoradcastManager注册的Receiver是本地Receiver
mLocalBroadcastManager.registerReceiver(mLocalReceiver,mIntentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销Receiver
mLocalBroadcastManager.unregisterReceiver(mLocalReceiver);
}
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received local broadcast",Toast.LENGTH_SHORT).show();
}
}
}
使用本地广播的优势:
- 可以明确地知道正在发送的广播不会离开本程序,因此不必担心数据泄露
- 其他的程序无法将广播发送到我们程序内部,因此不必担心安全漏洞
- 发送本地广播比全局广播更高效
四、应用技巧
来源:https://blog.csdn.net/sinat_37205087/article/details/102756748