本篇文章记述了 Android 的四大组件之一 —— BroadcastReceiver(播送接收者)。播送的作用、播送注册的形式、自定义播送、播送的类型以及在较新的 Android 零碎中应用 BroadcastReceiver 须要留神的问题。Android 利用与 Android 零碎和其余 Android 利用之间能够互相收发播送音讯,这与公布 - 订阅设计模式类似,这些播送会在所关注的事件产生时发送进来。
<!– more –>
对于零碎播送
举例来说,Android 零碎会在产生各种零碎事件时发送播送,例如系统启动或设施开始充电时。利用能够发送自定义播送来告诉其余利用它们可能感兴趣的事件(例如,一些新数据已下载)。利用能够注册接管特定的播送。播送收回后,零碎会主动将播送传送给批准接管这种播送的利用。
零碎会在产生各种零碎事件时主动发送播送,例如当零碎进入和退出航行模式时,零碎播送会被发送给所有批准接管相干事件的利用,或者在手机低电量的时候,零碎也会收回一个手机电量低的播送:
常见的零碎播送:
<!-- 开机播送 -->
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<!-- 开始充电播送 -->
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<!-- 低电量播送 -->
<action android:name="android.intent.action.BATTERY_LOW"/>
<!-- 利用卸载播送 -->
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<!-- 利用装置播送 -->
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<!-- 申明这个数据类型才能够收到利用装置 / 卸载的播送 -->
<data android:scheme="package"/>
<... />
零碎播送的注册
应用程序能够通过两种形式接管播送:通过清单文件申明的播送接收者和上下文注册的播送接收者。
动态注册
首先作为四大组件之一必定是要在清单文件申明的,创立一个 AppReceiver 用来接管 App 装置和卸载的播送,此类要继承 BroadcastReceiver:
public class AppReceiver extends BroadcastReceiver {
private static final String TAG = "AppReceiver";
@Override
public void onReceive(Context context, Intent intent) {
// 接管播送
if(intent != null){
// 判断收到的是什么播送
String action = intent.getAction();
assert action != null;
switch (action){
case Intent.ACTION_PACKAGE_REMOVED:
Log.i(TAG, "onReceive: ACTION_PACKAGE_REMOVED" + "利用被卸载");
break;
case Intent.ACTION_PACKAGE_ADDED:
Log.i(TAG, "onReceive: ACTION_PACKAGE_ADDED" + "利用被装置");
break;
}
}
}
}
AndroidManifest.xml
<!-- 动态注册播送接收者 -->
<receiver android:name=".AppReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!-- 利用卸载播送 -->
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<!-- 利用装置播送 -->
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<!-- 申明这个数据类型才能够收到利用装置 / 卸载的播送 -->
<data android:scheme="package"/>
</intent-filter>
</receiver>
在进行利用卸载和装置的时候,就能够收到对应的播送了:
动静注册
AppReceiver.java 还是和下面的一样,然而当初不在 AndroidManifest.xml 中申明,而是应用动静注册的形式,上面的例子演示了如何在 Activity 创立的动静的注册播送接收者:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private BroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 新建一个播送接收器
receiver = new AppReceiver();
// 接管哪些播送
IntentFilter intentFilter = new IntentFilter();
intentFilter.addDataScheme("package");
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
// 注册播送接收者
registerReceiver(receiver, intentFilter);
}
@Override
protected void onDestroy() {super.onDestroy();
// 勾销注册播送接收器(不勾销会导致内存透露)if(receiver != null){unregisterReceiver(receiver);
}
}
}
不过动静注册播送接收者千万别遗记在 Activity 销毁的时候解除之前注册的播送接收者。
动态注册须要在 AndroidManifest.xml 中申明,只有 APP 启动过一次,所动态注册的播送就会失效,无论以后的 APP 处于停止使用还是正在应用状态。只有相应的播送事件产生,零碎就会遍历所有的清单文件,告诉相应的播送接收者接管播送,而后调用播送接收者的 onReceiver 办法。
动静注册动静注册形式依赖于所注册的组件,当 APP 敞开后,组件对象都不在了动静注册的代码都不存在了,所动静注册监听的 Action 天然就不再失效了。动态注册的播送传播速度要远远慢于动静注册的播送。
如果即应用了动静注册,又应用了动态注册,那么动静动静注册的播送的优先级大于动态注册的播送。
播送的生命周期
1、BroadCastReceiver 的生命周期很短暂,当接管到播送的时候创立,当 onReceive() 办法完结后销毁
2、正因为 BroadCastReceiver 的申明周期很短暂,所以不要在播送接收器中去创立子线程做耗时的操作,因为播送接受者被销毁后,这个子过程就会成为空过程,很容易被杀死
3、因为 BroadCastReceiver 是运行在主线程的,所以不能间接在 BroadCastReceiver 中去做耗时的操作,否则就会呈现 ANR 异样,耗时的较长的工作最好放到 Service 中去实现。这里不能应用子线程来解决 , 因为 BroadcastReceiver 的生命周期很短,子线程可能还没有完结 BroadcastReceiver 就先完结了,BroadcastReceiver 一旦完结,此时 BroadcastReceiver 的所在过程很容易在零碎须要内存时被优先杀死,因为它属于空过程 (没有任何流动组件的过程),如果它的宿主过程被杀死,那么正在工作的子线程也会被杀死,所以采纳子线程来解决是不牢靠的。
自定义 Broadcast
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String MY_ACTION = "cn.tim.action.MY_ACTION";
public static final String MY_ACTION_EXTRA_KEY = "input_content";
private EditText etContent;
private CustomReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etContent = findViewById(R.id.et_content);
TextView tvShow = findViewById(R.id.tv_show);
receiver = new CustomReceiver();
receiver.tvShow = tvShow;
IntentFilter filter = new IntentFilter();
filter.addAction(MY_ACTION);
registerReceiver(receiver, filter);
}
public void send(View view) {
// 新建播送
Intent intent = new Intent(MY_ACTION);
// 放入播送要携带的数据
intent.putExtra(MY_ACTION_EXTRA_KEY, etContent.getText().toString());
sendBroadcast(intent);
}
@Override
protected void onDestroy() {super.onDestroy();
// 解除注册
if(receiver != null){unregisterReceiver(receiver);
}
}
}
CustomReceiver.java
public class CustomReceiver extends BroadcastReceiver {
TextView tvShow;
@Override
public void onReceive(Context context, Intent intent) {if(intent != null){String action = intent.getAction();
if(MainActivity.MY_ACTION.equals(action)){String inputContent = intent.getStringExtra(MainActivity.MY_ACTION_EXTRA_KEY);
tvShow.setText(inputContent);
}
}
}
}
不同的利用间通信,也是下面同样的代码,只有写雷同的 ACTION,那么就 OK 了:
Broadcast 分类
播送的发送,能够分为有序播送、无序播送、本地播送以及粘性播送。
有序播送
有序播送是一种分先后播送接收器的播送,播送接收者的优先级越高,越先接管播送。优先级高的播送先收到播送,收到播送后能够批改播送的内容,也能够拦挡播送不让播送向下传递。
如果在 CReceiver 中终止播送,那么优先级比拟低的 A 与 B 都收不到播送了。
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String MY_ACTION = "cn.tim.action.MY_ACTION";
public static final String KEY = "cn.tim.action.MY_ACTION";
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 新建播送
Intent intent = new Intent(MY_ACTION);
// 放入播送要携带的数据
Bundle bundle = new Bundle();
bundle.putInt(KEY, 100);
intent.putExtras(bundle);
//sendBroadcast(intent);
// 发送程序播送,参数二:权限
sendOrderedBroadcast(intent, null);
}
}
留神:如果要批改数据的话前提得是 Intent 发送数据得格局必须是 Bundle。
// 优先级 2
public class CReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {if(intent != null){String action = intent.getAction();
if(MainActivity.MY_ACTION.equals(action)){Bundle bundle = intent.getExtras();
Toast.makeText(context, "C:" + bundle.getInt(MainActivity.KEY), Toast.LENGTH_SHORT).show();
Bundle newBundle = new Bundle();
newBundle.putInt(MainActivity.KEY, 90);
setResultExtras(newBundle);
}
}
}
}
// 优先级 1
public class AReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {if(intent != null){String action = intent.getAction();
if(MainActivity.MY_ACTION.equals(action)){Bundle bundle = getResultExtras(true);
Toast.makeText(context, "A:" + bundle.getInt(MainActivity.KEY), Toast.LENGTH_SHORT).show();
Bundle newBundle = new Bundle();
newBundle.putInt(MainActivity.KEY, 80);
setResultExtras(newBundle);
}
}
}
}
// 优先级 0
public class BReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {if(intent != null){String action = intent.getAction();
if(MainActivity.MY_ACTION.equals(action)){Bundle bundle = getResultExtras(true);
Toast.makeText(context, "B:" + bundle.getInt(MainActivity.KEY), Toast.LENGTH_SHORT).show();}
}
}
}
无序播送
无序播送指所有与之匹配的播送接收者都能收到播送,没有先后顺序,直到没有播送接收者接管播送为止才会进行播送的传递。
默认状况下有播送发送时,零碎会遍历全副 APP 的 Receiver。如果想使得本 APP 的 Receiver 不被外界的播送所烦扰,能够在 Receiver 节点增加 android:exported=”false” 属性,这样零碎遍历全副 APP 清单文件的播送接收者时不会对本 App 的 Receiver 进行判断及解决。
本地播送
本地播送仅仅在 APP 内流传,其余的程序无奈收到这个播送。这种播送保障安全性,不会流传到外界。同时因为 LocalBroadcastManager 不须要用到跨过程机制,因而绝对 BroadcastReceiver 而言要更为高效。LocalBroadcastManager 只在动静播送时应用,动态播送不能应用 LocalBroadcastManager。
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String MY_NEW_ACTION = "cn.tim.action.MY_NEW_ACTION";
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 取得 LocalBroadcastManager 对象
localBroadcastManager = LocalBroadcastManager.getInstance(this);
// 动静注册播送
localReceiver = new LocalReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(MY_NEW_ACTION);
localBroadcastManager.registerReceiver(localReceiver, filter);
}
public void sendLocalBroadcast(View view) {
// 发送本地播送
Intent intent = new Intent(MY_NEW_ACTION);
localBroadcastManager.sendBroadcast(intent);
}
static class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){Toast.makeText(context,"Received LocalBroadcast!",Toast.LENGTH_SHORT).show();}
}
@Override
protected void onDestroy() {super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
}
new SDK 中应用播送
随着 Android 平台的倒退,它会不定期地更改零碎播送的行为形式。如果要在 Android 7.0(API 级别 24)或更高版本的 SDK 应用播送,必须留神以下更改:
Android 7.0 API 24
Android 7.0(API 级别 24)及更高版本不发送以下零碎播送:
ACTION_NEW_PICTURE
ACTION_NEW_VIDEO
此外,以 Android 7.0 及更高版本为指标平台的利用必须应用动静注册的形式,无奈在清单中申明播送接收器,所以当前所有播送间接全副应用动静注册的形式吧,如果非要用动态注册的形式,能够发送显式播送,(即指定指定包名再发送,然而咱们有时不晓得有谁要接管播送,所以显式播送用的比拟少),这个时候能够在发送播送的时候携带 intent.addFlags(0x01000000); 就能让播送冲破隐式播送限度,然而仍旧不倡议动态注册,还是动静注册比拟好。
Android 9.0 API 28
从 Android 9(API 级别 28)开始,NETWORK_STATE_CHANGED_ACTION 播送不再接管无关用户地位或个人身份数据的信息。通过 WLAN 接管的零碎播送不蕴含 SSID、BSSID 连贯信息或扫描后果,如果要获取这些信息,能够调用 WifiManager.getConnectionInfo()。
对于播送的文档能够看这里:《Receiving broadcasts》
原文地址:https://zouchanglin.cn/2020/1…