二、BroadcastReceiver
2.1、BroadcastReceiver 的使用
2.1.1、动态注册
动态注册指的是在代码中注册,等程序运行时才能够接收广播。下面是一个监听网络变化的广播接收器。
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONECTIVITY_CHANGE");
networkChangeReceiver = new NetWorkChangeReceiver();
rigisterReceiver(networkChangeReceiver,intentFilter);
- 广播接收器想要接受什么广播,就在 addAction 里添加相应的 action ,上述代码中的 android.net.conn.CONECTIVITY_CHANGE 就是在网络发生变化时,系统发出的广播。
- 动态注册的广播接收器一定要取消注册,unregisterReceiver()。
- 注意权限申请
2.1.2、静态注册
静态注册的广播接收器当 App 退出后,广播接收器仍然可以接收到广播并且进行相应的处理。
<application
android:allowBackup="true"
...>
......
<receiver android:name = ".BootCompleteReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
- 所有静态注册的广播接收器都要在 里注册
- 标签里加入想要接收的广播。
- 注意权限申请
2.2、发送广播
2.2.1、发送标准广播
标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序,也无法被截断。
public static MainActivity extends AppcompatActivity{
......
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
Intent intent = new Intent("com.chandelier.MY_BROADCAST");
sendBroadcast(intent);
}
});
......
}
......
}
2.2.2、发送有序广播
有序广播是一种同步执行的广播,在广播发出后,同一时刻只会有一个广播接收器能够收到这条广播信息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。也可以截断广播,这样后面的广播接收器就无法收到广播消息了。
public static MainActivity extends AppcompatActivity{
......
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
Intent intent = new Intent("com.chandelier.MY_BROADCAST");
sendOrderedBroadcast(intent);
}
});
......
}
......
}
既然是有序的,那么如何设定广播接收器的先后顺序呢?
答案是在注册广播接收器时通过优先级设定。
<application
android:allowBackup="true"
...>
......
<receiver android:name = ".MyBroadcastReceiver">
<intent-filter android:priority = "100">
<action android:name="com.chandelier.MY_BROADCAST"/>
</intent-filter>
</receiver>
</application>
如何截断广播?
public class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceiver(Context context, Intent intent){
abortBroadcast();
}
}
2.3、本地广播
以上的广播皆是系统全局广播,发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播,这样很容易会一起安全问题。为了解决安全性问题, android 引入了一套本地广播机制,使用 这个机制发出的挂个波之恶能够在应用程序的内部进行传递,并且广播接收器也只能接收来自于本应用程序发出的广播。
主要使用 LocalBroadcastManager 来对广播进行管理。
//获取实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//注册本地广播接收器
intentFilter = new IntentFilter();
intentFilter.addAction("com.chandelier.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.rigisterReceiver(localReceiver,intentFilter);
//发送本地广播
Intent intent = new Intent("com.chandelier.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
- 本地广播也需要取消注册
2.4、广播的注册过程
除动态注册的广播外,其他 android 的四大组件都是在应用安装时,由 PMS ( PackageManagerService )解析并注册的。
系统首先从 mPackageInfo 获取 IIntentReceiver 对象,然后采用跨进程的方式向 AMS 发送广播请求。所以注册广播真正的实现过程是在 AMS 中,AMS最终会把远程的 InnerReceiver 对象以及 IntentFilter 对象存储起来,这样广播注册过程就完成了。
public Intent registerReceiver(IApplicationThread caller,String callerPackage, IIntentReceiver receiver,IntentFilter filter, String permission, int userId){
...
mRegisterReceivers.put(receiver.asBinder(), rl);
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userID);
rl.add(bf);
if(!bf.debugVheck()){
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
...
}
2.5、广播的发送和接受过程
简单描述广播的发送接收过程:当通过send方法来发送广播时,AMS 会查找出匹配的广播接收器并将并将广播发送给它们处理。广播的发送和接收在本质上是一个过程的两个阶段。在具体的发送过程中,由于接收广播会调起应用程序,因此会在 ApplicationThread 中实现广播的接收。
默认情况下广播不会发送给已经停止的应用。因为 Intent 的 FLAG_EXCLUDE_STOPPED_PACKAGES 被 AMS 设置为默认标记位。