当前位置:   article > 正文

Android探索之BroadcastReceiver具体使用以及安全性探究_android 广播是线程安全的吗

android 广播是线程安全的吗

BroadcastReceiver简介:

    BroadcastReceiver是Android四大组件之一,广播是一种广泛运用的在应用程序之间传输信息的机制,而BroadcastReceiver 是对发送出来的广播进行过滤接收并响应的一类组件;广播接收者( BroadcastReceiver )用于接收广播 Intent ,广播 Intent 的发送是通过调用 Context.sendBroadcast() 、 Context.sendOrderedBroadcast() 来实现的。通常一个广播 Intent 可以被订阅了此 Intent 的多个广播接收者所接收。

广播的使用场景:

      1.同一app内部的同一组件内的消息通信(单个或多个线程之间);

      2.同一app内部的不同组件之间的消息通信(单个进程);

      3.同一app具有多个进程的不同组件之间的消息通信;

      4.不同app之间的组件之间消息通信;

      5.Android系统在特定情况下与App之间的消息通信。

广播的分类:

      普通广播:

       发送方式:Context.sendBroadcast()

       优点:完全异步,消息传递效率高,

       缺点:不能处理广播传给一个接收者,不能终止广播的传播

      有序广播:

       发送方式:Context.sendOrderedBroadcast()

       优点:可以根据广播接收者的优先级依次传播,广播接收者可以处理广播然后再传给一下广播接收者,也可以根据需要调用abortBroadcast()终止广播传播。

       缺点:效率低  

 

广播的使用方式:

动态注册:

  1. //注册广播
  2. private void registerReceiver(){
  3. IntentFilter dynamicFilter = new IntentFilter();
  4. dynamicFilter.addAction(ActionCodes.DYNAMICACTION);//添加动态广博Action
  5. registerReceiver(dynamicReceiver, dynamicFilter);
  6. }
  7. //解除注册
  8. private void unRegisterReceiver()
  9. {
  10. unregisterReceiver(dynamicReceiver);
  11. }
  12. //动态广播的Receiver
  13. private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() {
  14. @Override
  15. public void onReceive(Context context, Intent intent) {
  16. if(intent.getAction().equals(ActionCodes.DYNAMICACTION)){ //动作检测
  17. String msg = intent.getStringExtra("msg");
  18. String finalMsg= String.format("%s%s","CActivity----->收到广播:",msg);
  19. Log.e("dynamicReceiver",finalMsg);
  20. Toast.makeText(context, finalMsg, Toast.LENGTH_SHORT).show();
  21. }
  22. }
  23. };

一般情况在Activity/Fragment 的onCreate/onStart/onResume 中注册, 在onDestory/onStop/onPause 中解除注册,根据不同的需求选择不能的生命周期函数。

静态注册:

  1. <receiver
  2. android:name=".StaticReceiver"
  3. android:enabled="true"
  4. android:exported="true">
  5. <intent-filter android:priority="100">
  6. <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" />
  7. </intent-filter>
  8. </receiver>

发送广播:

  1. //发送普通广播
  2. Intent intent = new Intent();
  3. intent.setAction(ActionCodes.DYNAMICACTION);//设置Action
  4. intent.putExtra("msg", "我是普通广播(动态注册)");//添加附加信息
  5. sendBroadcast(intent);
  6. //发送有序广播
  7. Intent intent = new Intent();
  8. intent.setAction(ActionCodes.DYNAMICACTION);//设置Action
  9. intent.setPackage(getPackageName());//设置包名
  10. intent.putExtra("msg", "我是有序广播(动态注册)");//添加附加信息
  11. sendOrderedBroadcast(intent,null);

以上基本上可以满足广播的基本使用了,接下来我们在写个测试程序:分别在A,B,C三个Activity中动态注册广播,分别发送普通广播和和有序广播。

发送普通广播接收顺序:

分别给A,B,C三个Activity中动态注册广播的优先级设置未100,500,1000接收顺序:

附上设置优先级方式:

  1. IntentFilter dynamicFilter = new IntentFilter();
  2. dynamicFilter.addAction(ActionCodes.DYNAMICACTION);//添加动态广播的Action
  3. dynamicFilter.setPriority(1000);//设置优先级
  4. registerReceiver(dynamicReceiver, dynamicFilter);

上文已知有序广播可以修改广播信息传递给下一级优先级低的接收者,我们让BActivity修改 让AActivity接收:

BActivity 广播实现

  1. //动态广播的Receiver
  2. private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() {
  3. @Override
  4. public void onReceive(Context context, Intent intent) {
  5. if(intent.getAction().equals(ActionCodes.DYNAMICACTION)){ //动作检测
  6. String msg = intent.getStringExtra("msg");
  7. String finalMsg= String.format("%s%s","BActivity----->收到广播:",msg);
  8. Log.e("dynamicReceiver",finalMsg);
  9. Toast.makeText(context, finalMsg, Toast.LENGTH_SHORT).show();
  10. if(isOrderedBroadcast()) {
  11. //创建一个Bundle对象,并存入数据
  12. Bundle bundle = new Bundle();
  13. bundle.putString("msg", msg + "来自BActivity");
  14. //将bundle放入结果中
  15. setResultExtras(bundle);
  16. //取消Broadcast的继续发送
  17. //abortBroadcast();
  18. }
  19. }
  20. }
  21. };

AActivity 如何接收:

  1. //动态广播的Receiver
  2. private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() {
  3. @Override
  4. public void onReceive(Context context, Intent intent) {
  5. if(intent.getAction().equals(ActionCodes.DYNAMICACTION)) { //动作检测
  6. String msg = intent.getStringExtra("msg");
  7. String finalMsg = String.format("%s%s", "AActivity----->收到广播:", msg);
  8. Log.e("dynamicReceiver", finalMsg);
  9. if (isOrderedBroadcast()) {
  10. Bundle bundle = getResultExtras(true);//接收来自上一级优先级较高的广播修改的信息
  11. String from = bundle.getString("msg");
  12. if (TextUtils.isEmpty(from)) {
  13. return;
  14. }
  15. Log.e("dynamicReceiver", String.format("%s%s", "AActivity----->收到广播:", from));
  16. Toast.makeText(context, finalMsg, Toast.LENGTH_SHORT).show();
  17. }
  18. }
  19. }
  20. };

运行结果:

有序广播如何终止广播传播:

  1. // 终止Broadcast的继续发送
  2. abortBroadcast();

运行结果:

静态注册的广播上述测试运行结果一致,设置优先级方式不同而已:

  1. <receiver
  2. android:name=".AStaticReceiver"
  3. android:enabled="true"
  4. android:exported="true">
  5. <intent-filter android:priority="100"><!--设置优先级-->
  6. <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" />
  7. </intent-filter>
  8. </receiver>

接下来测试一下app应用之间发送广播,发送方式也是通过隐式Intent方式:

动态注册广播接收情况:

普通广播:

有序广播:

静态注册广播接收情况:

普通广播:

有序广播:

   看了上述测试结果基本上和app内运行效果一模一样,所以按照上述那种注册方式和使用方式,一旦app被反编译之后有一定的安全隐患,如何安全的传输呢?

第一种方式:

静态注册广播可以设置:android:exported="false"

  1. <receiver
  2. android:name=".AStaticReceiver"
  3. android:enabled="true"
  4. android:exported="false" <!--设置只能接收app内广播 -->
  5. >
  6. <intent-filter android:priority="100"><!--设置优先级-->
  7. <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" />
  8. </intent-filter>
  9. </receiver>

第二种方式:通过设置发送的广播只能app内接收

  1. Intent intent = new Intent();
  2. intent.setAction(ActionCodes.DYNAMICACTION);//设置Action
  3. intent.setPackage(getPackageName());//设置包名使广播只能被包名的app内接收者接收
  4. intent.putExtra("msg", "我是普通广播(动态注册)");//添加附加信息
  5. sendBroadcast(intent);

第三种方式通过自定义权限:通过上述两种方式只能达到屏蔽外来广播以及广播只在app内传播,无法实现app之间安全发送广播

自定义权限:

  1. <permission android:name="com.whoislcj.broadcastreceiver.MySelfBroadcastReceiver"
  2.   android:protectionLevel="normal"/>
<uses-permission android:name="com.whoislcj.broadcastreceiver.MySelfBroadcastReceiver"/>

自定义权限时必须同时指定 protectionLevel 属性值,系统根据该属性值确定自定义权限的使用方式

属性值限定方式
normal默认值。较低风险的权限,对其他应用,系统和用户来说风险最小。系统在安装应用时会自动批准授予应用该类型的权限,不要求用户明确批准(虽然用户在安装之前总是可以选择查看这些权限)
dangerous较高风险的权限,请求该类型权限的应用程序会访问用户私有数据或对设备进行控制,从而可能对用户造成负面影响。因为这种类型的许可引入了潜在风险,所以系统可能不会自动将其授予请求的应用。例如,系统可以向用户显示由应用请求的任何危险许可,并且在继续之前需要确认,或者可以采取一些其他方法来避免用户自动允许
signature只有在请求该权限的应用与声明权限的应用使用相同的证书签名时,系统才会授予权限。如果证书匹配,系统会自动授予权限而不通知用户或要求用户的明确批准
signatureOrSystem系统仅授予Android系统映像中与声明权限的应用使用相同的证书签名的应用。请避免使用此选项,“signature”级别足以满足大多数需求,“signatureOrSystem”权限用于某些特殊情况

动态注册:

  1. IntentFilter dynamicFilter = new IntentFilter();
  2. dynamicFilter.addAction(ActionCodes.DYNAMICACTION);//添加动态广播的Action
  3. dynamicFilter.setPriority(500);
  4. //设置权限
  5. registerReceiver(dynamicReceiver, dynamicFilter,ActionCodes.MYPERMISSION,null);

静态注册:

  1. <receiver
  2. android:name=".BStaticReceiver"
  3. android:enabled="true"
  4. android:exported="true"
  5. <!--设置权限-->
  6. android:permission="com.whoislcj.broadcastreceiver.MySelfBroadcastReceiver">
  7. <intent-filter android:priority="500">
  8. <action android:name="com.whoislcj.broadcastreceiver.staticreceiver" />
  9. </intent-filter>
  10. </receiver>

发送广播:

  1. //普通广播
  2. sendBroadcast(intent,ActionCodes.MYPERMISSION);
  3. //有序广播
  4. sendOrderedBroadcast(intent,ActionCodes.MYPERMISSION);

 

第四种方式:通过LocalBroadcastManager方式

 注册:

LocalBroadcastManager.getInstance(getInstance()).registerReceiver(receiver, filter);

解除注册:

LocalBroadcastManager.getInstance(getInstance()).unregisterReceiver(receiver);

发送广播:

LocalBroadcastManager.getInstance(getInstance()).sendBroadcastSync(intent);
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/784534
推荐阅读
相关标签
  

闽ICP备14008679号