本篇文章记述了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。
// 优先级 2public 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); } } }}// 优先级 1public 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); } } }}// 优先级 0public 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_PICTUREACTION_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...