概述
广播就像一个全局的监听器。
按照辐射范围分为:本地广播(单个App内有效),全局广播(系统范围内有效,可多个App间广播)。
按照广播顺序分为:
- 标准广播:是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
- 有序广播:是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
接收系统广播
Android 内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条广播,等等。如果想要接收到这些广播,就需要使用广播接收器,下面我们就来看一下它的具体用法。<br /> 广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广播接收器就能够收到该广播,并在内部处理相应的逻辑。注册广播的方式一般有两种,在代码中注册和在 AndroidManifest.xml 中注册,其中前者也被称为动态注册,后者也被称为静态注册。
动态注册_实现监听网络变化
动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在 onCreate() 方法中的。
创建一个广播接收器,即,新建一个类,让它继承自 BroadcastReceiver ,并重写父类的 onReceive() 方法就行了。这样当有广播到来时, onReceive() 方法就会得到执行,具体的逻辑就可以在这个方法中处理。下面是态注册实现监听网络变化的代码:
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter; //用于过滤广播,指定需要接收的广播
private NetworkChangeReceiver networkChangeReceiver; //自定义的广播接收器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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 connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); //获取系统服务类实例,该类专门用于管理网络连接
NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo(); //获取网络连通性
if (networkInfo != null && networkInfo.isAvailable()) {
Toast.makeText(context, "network is available",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "network is unavailable",Toast.LENGTH_SHORT).show()
}
}
}
}
当然在获取网络情况时需要具有用户权限才行。
静态注册_实现开机 Tost
静态注册可以让程序在未启动的情况下就能接收到广播,编写好广播接收器后需要在 AndroidManifest.xml 中注册。当然也可以直接新建broadcast让系统来自动注册到AndroidManifest.xml中
以开机实现Tost提示为例:
创建广播接收器
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show(); //接收到广播后的具体逻辑,提示启动完成
}
}
AndroidManifest.xml 中注册该广播接收器
<manifest xmlns:android="http:/schemas.android.com/apk/res/android” package="com.example.broadcasttest”>
<!-- 申明权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true”
android:icon="@mipmap/ic_launcher”
android:label="@string/app_name”
android:supportsRtl="true”
android:theme="@style/AppTheme”>
...
<!-- 静态注册广播 -->
<receiver
android:name=“.BootCompleteReceiver" <!-- 指定注册的广播接收器 -->
android:enabled="true" <!-- 是否启用该广播接收器 -->
android:exported="true"> <!-- 是否允许该广播接收器接收本程序以外的广播 -->
<intent-filter> <!-- 指定接收哪些广播 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<intent-filter>
</receiver>
</application>
</manifest>
发送自定义广播
发送标准广播
- 定义广播接收器
//定义一个广播接收器
class MyBroadcastReceiver extends BroadcastReceiver {
@Override //接收广播后回调方法
public void onReceive(Context context, Intent intent) {
//接收到广播后的逻辑
...
}
}
AndroidManifest.xml 中注册该广播接收器
<manifest xmlns:android="http:/schemas.android.com/apk/res/android” package="com.example.broadcasttest”> <application android:allowBackup="true” android:icon="@mipmap/ic_launcher” android:label="@string/app_name” android:supportsRtl="true” android:theme="@style/AppTheme”> ... <!-- 静态注册广播 --> <receiver android:name=“.MyBroadcastReceiver" <!-- 指定注册的广播接收器 --> android:enabled="true" <!-- 是否启用该广播接收器 --> android:exported="true"> <!-- 是否允许该广播接收器接收本程序以外的广播 --> <intent-filter> <!-- 指定接收哪些广播 --> <action android:name="com.example.broadcasttest.MY_BROADCAST" /> <!— 这里是自定义的一个广播 --> <intent-filter> </receiver> </application> </manifest>
发送自定义的广播
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST”); //创建一个自定义广播的Intent。也可以在Intent中携带一些数据 sendBroadcast(intent); //调用context的方法发送广播
发送有序广播
- 与发送标准广播相比,发送有序广播只需要改动一行代码,即将 sendBroadcast() 方法改成 sendOrderedBroadcast() 方法。sendOrderedBroadcast() 方法接收两个参数,第一个参数仍然是 Intent,第二个参数是一个与权限相关的字符串,一般传入 null 即可。
那么该如何设定广播接收器的先后顺序呢?当然是在注册的时候进行设定的了,修改 AndroidManifest.xml 中的代码,如下所示:
<manifest xmlns:android="http:/schemas.android.com/apk/res/android” package="com.example.broadcasttest”> <application android:allowBackup="true” android:icon="@mipmap/ic_launcher” android:label="@string/app_name” android:supportsRtl="true” android:theme="@style/AppTheme”> ... <!-- 静态注册广播 --> <receiver android:name=“.MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <!--给广播接收器设置优先级 --> <action android:name="com.example.broadcasttest.MY_BROADCAST" /> <intent-filter> </receiver> </application> </manifest>
通过 android:priority 属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播。这里将 MyBroadcastReceiver 的优先级设成了100。
既然已经获得了接收广播的优先权,那么 MyBroadcastReceiver 就可以选择是否允许广播继续传递了。修改 MyBroadcastReceiver 中的代码,如下所示:
//广播接收器 class MyBroadcastReceiver extends BroadcastReceiver { @Override //接收广播后回调方法 public void onReceive(Context context, Intent intent) { abortBroadcast(); //截断广播,此时后面的广播接收器将无法收到该条广播 } }
本地广播
只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播。无需自己编写广播接收器,系统提过了一个 LocalBroadcastManager 来对广播进行管理,并提供了发送广播和注册广播接收器的方法。伪代码如下:
//发送本地广播
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(context);
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_TOPIC_PUBLISH_NEW).putExtra(Constant.EXTRA_INFO_TOPIC, topic));
//接收本地广播(另一个页面)
private void registerBroadcastReceiver() {
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Constant.ACTION_TOPIC_PUBLISH_NEW); //指定接收哪些本地广播
intentFilter.addAction(Constant.ACTION_TOPIC_MANAGER_REMOVE);
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); //获取具体的action来辨别具体广播
switch (action) {
case Constant.ACTION_TOPIC_PUBLISH_NEW:
Topic topicNew = intent.getParcelableExtra(Constant.EXTRA_INFO_TOPIC);
//收到这条广播后的具体逻辑
......
break;
case Constant.ACTION_TOPIC_MANAGER_REMOVE:
//收到这条广播后的具体逻辑
......
break;
}
//当接收广播的页面销毁时需将其广播接收器释放掉
@Override
public void onDestroy() {
super.onDestroy();
broadcastManager.unregisterReceiver(broadcastReceiver);
}
和全局广播相比本地广播具有以下优势:
- 可以明确地知道正在发送的广播不会离开我们的程序,因此不必担心机密数据泄漏。
- 其他的程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患。
- 发送本地广播比发送系统全局广播将会更加高效。
注意
不要在 广播接收器的 onReceive() 方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当 onReceive() 方法运行了较长时间而没有结束时,程序就会报错。因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动一个服务等。