2.7Receiver广播基础
目录介绍
- 01.什么是广播Broadcast
- 02.广播Broadcast作用
- 03.广播Broadcast分类
- 04.静态注册BroadCast
- 4.1 发送标准广播
- 4.2 发送有序广播
- 05.动态注册BroadCast
- 06.发送本地广播
- 07.使用私有权限
01.什么是广播Broadcast
- 在 Android 系统中,广播(Broadcast)是在组件之间传播数据的一种机制,这些组件可以位于不同的进程中,起到进程间通信的作用。
- BroadcastReceiver 是对发送出来的Broadcast进行过滤、接受和响应的组件。首先将要发送的消息和用于过滤的信息(Action,Category)装入一个 Intent对象,然后通过调用Context.sendBroadcast()、sendOrderBroadcast() 方法把 Intent 对象以广播形式发送出去。 广播发送出去后,所以已注册的 BroadcastReceiver 会检查注册时的 IntentFilter 是否与发送的 Intent 相匹配,若匹配则会调用 BroadcastReceiver 的 onReceiver() 方法
- 所以当我们定义一个 BroadcastReceiver 的时候,都需要实现 onReceiver() 方法。BroadcastReceiver 的生命周期很短,在执行 onReceiver() 方法时才有效,一旦执行完毕,该Receiver 的生命周期就结束了。
02.广播Broadcast作用
- 用于监听 / 接收 应用发出的广播消息,并做出响应
- 应用场景
- a.不同组件之间通信(包括应用内 / 不同应用之间)
- b.与
Android
系统在特定情况下的通信:如当电话呼入时、网络可用时 - c.多线程通信
03.广播Broadcast分类
- Android中的广播分为两种类型,标准广播和有序广播
- 标准广播
- 标准广播是一种完全异步执行的广播,在广播发出后所有的广播接收器会在同一时间接收到这条广播,之间没有先后顺序,效率比较高,且无法被截断。
- 有序广播
- 有序广播是一种同步执行的广播,在广播发出后同一时刻只有一个广播接收器能够接收到, 优先级高的广播接收器会优先接收,当优先级高的广播接收器的 onReceiver() 方法运行结束后,广播才会继续传递,且前面的广播接收器可以选择截断广播,这样后面的广播接收器就无法接收到这条广播了。
- 标准广播
04.静态注册BroadCast
- 静态注册在清单文件配置
- 即在清单文件中为 BroadcastReceiver 进行注册,使用**< receiver >**标签声明,并在标签内用 < intent-filter > 标签设置过滤器。这种形式的BroadcastReceiver的生命周期伴随着整个应用,如果这种方式处理的是系统广播,那么不管应用是否在运行,该广播接收器都能接收到该广播。
- 代码如下所示
- 首先,继承 BroadcastReceiver 类创建一个用于接收标准广播的Receiver,在 onReceive() 方法中取出 Intent 传递来的字符串
public class NormalReceiver extends BroadcastReceiver { public NormalReceiver() { } @Override public void onReceive(Context context, Intent intent) { String msg = intent.getStringExtra("Msg"); LogUtils.i("广播NormalReceiver------"+msg); } }
4.1 发送标准广播
- 在清单文件中声明的 BroadcastReceiver ,必须包含值为 NORMAL_ACTION 字符串的 action 属性,该广播接收器才能收到以下代码中发出的广播
- 发送标准广播调用的是 sendBroadcast(Intent) 方法
public class MainActivity extends AppCompatActivity { private final String NORMAL_ACTION = "com.example.normal.receiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void sendBroadcast(View view) { Intent intent = new Intent(NORMAL_ACTION); intent.putExtra("Msg", "逗比"); sendBroadcast(intent); } }
- 在清单文件中注册 BroadcastReceiver
<application> <receiver android:name=".NormalReceiver"> <intent-filter> <action android:name="com.example.normal.receiver" /> </intent-filter> </receiver> </application>
4.2 发送有序广播
- 首先,继承 BroadcastReceiver 类创建三个用于接收有序广播的Receiver,名字依次命名为 OrderReceiver_1、OrderReceiver_2、OrderReceiver_3。
- 此外,既然 Receiver 在接收广播时存在先后顺序,那么 Receiver 除了能从发送广播使用的 Intent 接收数据外,优先级高的 Receiver 也能在处理完操作后向优先级低的 Receiver 传送处理结果。
public class OrderReceiver_1 extends BroadcastReceiver { private final String TAG = "OrderReceiver_1"; public OrderReceiver_1() { } @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "OrderReceiver_1被调用了"); //取出Intent当中传递来的数据 String msg = intent.getStringExtra("Msg"); Log.e(TAG, "OrderReceiver_1接收到的值: " + msg); //向下一优先级的Receiver传递数据 Bundle bundle = new Bundle(); bundle.putString("Data", "(Hello)"); setResultExtras(bundle); } } public class OrderReceiver_2 extends BroadcastReceiver { private final String TAG = "OrderReceiver_2"; public OrderReceiver_2() { } @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "OrderReceiver_2被调用了"); //取出上一优先级的Receiver传递来的数据 String data = getResultExtras(true).getString("Data"); Log.e(TAG, "从上一优先级的Receiver传递来的数据--" + data); //向下一优先级的Receiver传递数据 Bundle bundle = new Bundle(); bundle.putString("Data", "(叶应是叶)"); setResultExtras(bundle); } } public class OrderReceiver_3 extends BroadcastReceiver { private final String TAG = "OrderReceiver_3"; public OrderReceiver_3() { } @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "OrderReceiver_3被调用了"); //取出上一优先级的Receiver传递来的数据 String data = getResultExtras(true).getString("Data"); Log.e(TAG, "从上一优先级的Receiver传递来的数据--" + data); } }
- 在清单文件中对三个 Receiver 进行注册,指定相同的 action 属性值,Receiver 之间的优先级使用 priority 属性来判定,数值越大,优先级越高
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".OrderReceiver_1"> <intent-filter android:priority="100"> <action android:name="com.example.order.receiver" /> </intent-filter> </receiver> <receiver android:name=".OrderReceiver_2"> <intent-filter android:priority="99"> <action android:name="com.example.order.receiver" /> </intent-filter> </receiver> <receiver android:name=".OrderReceiver_3"> <intent-filter android:priority="98"> <action android:name="com.example.order.receiver" /> </intent-filter> </receiver> </application>
- 发送有序广播调用的是 **sendOrderedBroadcast(Intent,String)**方法,String参数值在自定义权限时使用,下边会有介绍
public class MainActivity extends AppCompatActivity { private final String NORMAL_ACTION = "com.example.normal.receiver"; private final String ORDER_ACTION = "com.example.order.receiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void sendBroadcast(View view) { Intent intent = new Intent(NORMAL_ACTION); intent.putExtra("Msg", "Hi"); sendBroadcast(intent); } public void sendOrderBroadcast(View view) { Intent intent = new Intent(ORDER_ACTION); intent.putExtra("Msg", "Hi"); sendOrderedBroadcast(intent, null); } }
05.动态注册BroadCast
- 动态注册 BroadcastReceiver 是在代码中定义并设置好一个 IntentFilter 对象,然后在需要注册的地方调用 Context.registerReceiver() 方法,调用 Context.unregisterReceiver() 方法取消注册,此时就不需要在清单文件中注册 Receiver 了
- 这里采用在 Service 中注册广播接收器的形式,分别在注册广播接收器、取消注册广播接受器和接收到广播时输出Log。
public class BroadcastService extends Service { private BroadcastReceiver receiver; private final String TAG = "BroadcastService"; public BroadcastService() { } @Override public void onCreate() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(MainActivity.ACTION); receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "BroadcastService接收到了广播"); } }; registerReceiver(receiver, intentFilter); Log.e(TAG, "BroadcastService注册了接收器"); super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); Log.e(TAG, "BroadcastService取消注册接收器"); } @Override public IBinder onBind(Intent intent) { return null; } }
- 提供启动服务,停止服务、发送广播的方法
public class MainActivity extends AppCompatActivity { public final static String ACTION = "com.example.receiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startService(View view) { Intent intent = new Intent(this, BroadcastService.class); startService(intent); } public void sendBroadcast(View view) { Intent intent = new Intent(ACTION); sendBroadcast(intent); } public void stopService(View view) { Intent intent = new Intent(this, BroadcastService.class); stopService(intent); } }
- 动态广播最好在Activity的onResume()注册、onPause()注销。
- 原因:对于动态广播,有注册就必然得有注销,否则会导致内存泄露
- 重复注册、重复注销也不允许
06.发送本地广播
- 之前发送和接收到的广播全都是属于系统全局广播,即发出的广播可以被其他应用接收到,而且也可以接收到其他应用发送出的广播,这样可能会有不安全因素
- 因此,在某些情况下可以采用本地广播机制,使用这个机制发出的广播只能在应用内部进行传递,而且广播接收器也只能接收本应用内自身发出的广播
- 本地广播是使用 LocalBroadcastManager 来对广播进行管理
函数 作用 LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter) 注册Receiver LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver); 注销Receiver LocalBroadcastManager.getInstance(this).sendBroadcast(Intent) 发送异步广播 LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent) 发送同步广播 - 首先,创建一个 BroadcastReceiver 用于接收本地广播
public class LocalReceiver extends BroadcastReceiver { private final String TAG = "LocalReceiver"; public LocalReceiver() { } @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "接收到了本地广播"); } }
- 之后就是使用 LocalBroadcastManager 对 LocalReceiver 进行注册和解除注册了
private LocalBroadcastManager localBroadcastManager; private LocalReceiver localReceiver; private final String LOCAL_ACTION = "com.example.local.receiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); localBroadcastManager = LocalBroadcastManager.getInstance(this); localReceiver = new LocalReceiver(); IntentFilter filter = new IntentFilter(LOCAL_ACTION); localBroadcastManager.registerReceiver(localReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(batteryReceiver); localBroadcastManager.unregisterReceiver(localReceiver); } public void sendLocalBroadcast(View view) { Intent intent = new Intent(LOCAL_ACTION); localBroadcastManager.sendBroadcast(intent); }
- 需要注意
- 本地广播是无法通过静态注册的方式来接收的,因为静态注册广播主要是为了在程序未启动的情况下也能接收广播,而本地广播是应用自己发送的,此时应用肯定是启动的了
07.使用私有权限
- 使用动态注册广播接收器存在一个问题,即系统内的任何应用均可监听并触发我们的 Receiver 。通常情况下我们是不希望如此的
- 解决办法之一是在清单文件中为 < receiver > 标签添加一个 android:exported="false" 属性,标明该 Receiver 仅限应用内部使用。这样,系统中的其他应用就无法接触到该 Receiver 了
- 此外,也可以选择创建自己的使用权限,即在清单文件中添加一个 < permission > 标签来声明自定义权限
<permission android:name="com.example.permission.receiver" android:protectionLevel="signature" />
- 自定义权限时必须同时指定 protectionLevel 属性值,系统根据该属性值确定自定义权限的使用方式
属性值 限定方式 normal 默认值。较低风险的权限,对其他应用,系统和用户来说风险最小。系统在安装应用时会自动批准授予应用该类型的权限,不要求用户明确批准(虽然用户在安装之前总是可以选择查看这些权限) dangerous 较高风险的权限,请求该类型权限的应用程序会访问用户私有数据或对设备进行控制,从而可能对用户造成负面影响。因为这种类型的许可引入了潜在风险,所以系统可能不会自动将其授予请求的应用。例如,系统可以向用户显示由应用请求的任何危险许可,并且在继续之前需要确认,或者可以采取一些其他方法来避免用户自动允许 signature 只有在请求该权限的应用与声明权限的应用使用相同的证书签名时,系统才会授予权限。如果证书匹配,系统会自动授予权限而不通知用户或要求用户的明确批准 signatureOrSystem 系统仅授予Android系统映像中与声明权限的应用使用相同的证书签名的应用。请避免使用此选项,“signature”级别足以满足大多数需求,“signatureOrSystem”权限用于某些特殊情况 - 首先,新建一个新的工程,在它的清单文件中创建一个自定义权限,并声明该权限。protectionLevel 属性值设为“signature”
<permission android:name="com.example.permission.receiver" android:protectionLevel="signature" /> <uses-permission android:name="com.example.permission.receiver" />
- 然后,发送含有该权限声明的 Broadcast 。这样,只有使用相同证书签名且声明该权限的应用才能接收到该 Broadcast 了
private final String PERMISSION_PRIVATE = "com.example.permission.receiver"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void sendPermissionBroadcast(View view) { sendBroadcast(new Intent("Hi"), PERMISSION_PRIVATE); }
- 回到之前的工程。首先在清单文件中声明权限
<uses-permission android:name="com.example.permission.receiver" />
- 创建一个 BroadcastReceiver
public class PermissionReceiver extends BroadcastReceiver { private final String TAG = "PermissionReceiver"; public PermissionReceiver() { } @Override public void onReceive(Context context, Intent intent) { Log.e(TAG, "接收到了私有权限广播"); } }
- 然后注册广播接收器。因为 AndroidStudio在调试的时候会使用相同的证书为每个应用签名,所以,在之前新安装的App发送出广播后,PermissionReceiver 就会输出 Log 日志
private final String PERMISSION_PRIVATE = "com.example.permission.receiver"; private PermissionReceiver permissionReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); IntentFilter intentFilter1 = new IntentFilter("Hi"); permissionReceiver = new PermissionReceiver(); registerReceiver(permissionReceiver, intentFilter1, PERMISSION_PRIVATE, null); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(permissionReceiver); }
广播 1.三方app内部自定义广播 2.如何监听三方广播的状态,是否发送成功
查看Android系统广播发送记录 dumpsys |grep BroadcastRecord 从上到下,是按照从新到旧的顺序排列的,也就是说第一行是系统最新发出的一个广播。
用于监测最近一段时间内发出的全局广播 adb shell dumpsys activity | grep BroadcastRecord |grep -v android. grep -v android.意思是不显示包含android.字符的广播 dumpsys显示的广播在10秒左右就会被清除,所以在广播发送以后短时间内才有效
1.0.2.3 广播有几种形式?他们分别有什么特点,如何使用广播?广播发送和接收原理是什么?Android中哪些需要用到广播?
- 广播有几种形式
- 普通广播:一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们接收的先后是随机的。
- 有序广播:一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播接收器是有先后顺序的,且优先级(priority)高的广播接收器会先收到广播消息。有序广播可以被接收器截断使得后面的接收器无法收到它。
- 本地广播:发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收本应用程序发出的广播。
- 粘性广播:这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到此条广播。
- 广播的两种注册形式技术博客大总结
- 广播的注册有两种方法:一种在活动里通过代码动态注册,另一种在配置文件里静态注册。两种方式的相同点是都完成了对接收器以及它能接收的广播值这两个值的定义;不同点是动态注册的接收器必须要在程序启动之后才能接收到广播,而静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机完成后系统发出的广播就只能用静态注册了。
- 动态注册
- 需要使用广播接收者时,执行注册的代码,不需要时,执行解除注册的代码。安卓中有一些广播接收者,必须使用代码注册,清单文件注册是无效的。
- 静态注册
- 可以使用清单文件注册。广播一旦发出,系统就会去所有清单文件中寻找,哪个广播接收者的action和广播的action是匹配的,如果找到了,就把该广播接收者的进程启动起来。
- 广播发送和接收原理是什么[binder如何运作的]?
- 继承BroadcastReceiver,重写onReceive()方法。
- 通过Binder机制向ActivityManagerService注册广播。
- 通过Binder机制向ActivityMangerService发送广播。
- ActivityManagerService查找符合相应条件的广播(IntentFilter/Permission)的BroadcastReceiver,将广播发送到BroadcastReceiver所在的消息队列中。
- BroadcastReceiver所在消息队列拿到此广播后,回调它的onReceive()方法。
- Android中哪些需要用到广播?
- Android中:系统在运行过程中,会产生会多事件,那么某些事件产生时,比如:电量改变、收发短信、拨打电话、屏幕解锁、开机,系统会发送广播,只要应用程序接收到这条广播,就知道系统发生了相应的事件,从而执行相应的代码。使用广播接收者,就可以收听广播
- 广播的生命周期是怎样的?
- a.广播接收者的生命周期非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁;
- b.广播接收者中不要做一些耗时的工作,否则会弹出 Application No Response错误对话框;
- c.最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉;
- d.耗时的较长的工作最好放在服务中完成;
- 接入极光推送广播原理分析
- 思考一下,配置自定义极光推送的广播,然后在清单文件中注册,添加一些action和Category,那么广播是怎么注册和接受消息呢?
- 首先将要发送的消息和用于过滤的信息(Action,Category)装入一个 Intent对象,然后通过调用Context.sendBroadcast()、sendOrderBroadcast() 方法把 Intent 对象以广播形式发送出去。 广播发送出去后,所以已注册的 BroadcastReceiver 会检查注册时的 IntentFilter 是否与发送的 Intent 相匹配,若匹配则会调用 BroadcastReceiver 的 onReceiver() 方法
其他介绍
01.关于博客汇总链接
02.关于我的博客
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yczbj/activities
- 简书:http://www.jianshu.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
- 开源中国:https://my.oschina.net/zbj1618/blog
- 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 邮箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e