乐趣区

关于android:Android四大组件详解之BroadcastReceiver广播接收者

Android 四大组件详解 —BroadcastReceicer 播送接收者
播送有两个角色,一个是播送发送者,另一个是播送接收者。
播送依照类型分为两种,一种是全局播送,另一种是本地播送
全局播送:就是收回的播送被其余任意应用程序接管,或者能够接管来自其余任意应用程序的播送。
本地播送:则是只能在应用程序外部进行传递的播送,播送接收器也只能接管外部的播送,不能接管其余应用程序的播送
播送依照机制分两种,一种是规范播送,一种是有序播送
规范播送:是一种异步的形式来进行流传的,所有接收者都会接管事件,不能够被拦挡,不能够被批改
有序播送:是一种同步执行的播送,依照优先级,一级一级的向下传递,接收者能够批改播送数据,也能够终止播送事件。
一:应用播送接收器接管播送
1. 定义一个 TestReceiver 类继承播送接收者 BroadcastReceiver,复写其中的 onReceive() 办法

public class TestReceiver extends BroadcastReceiver {
    private static final String TAG="TestReceiver";
 @Override
 public void onReceive(Context context, Intent intent) {Log.d(TAG,"onReceive()");
 }
}

2. 对播送进行注册
注册形式有两种,一种是动静注册,一种是动态注册
动静注册

public class ReceActivity extends AppCompatActivity {
    private TestReceiver receiver;
 private IntentFilter intentFilter;
 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_rece);
 receiver=new TestReceiver();
 intentFilter=new IntentFilter();
 intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
 // 当网络发生变化的时候,零碎播送会收回值为 android.net.conn.CONNECTIVITY_CHANGE 这样的一条播送
 registerReceiver(receiver,intentFilter);
 }
}
后果:切换网络变动
D/TestReceiver: onReceive()

动态注册,像这种零碎播送,android8.0 以上对动态播送注册做了严格限度,就没法承受到网络变动的播送

<receiver android:name=".TestReceiver"
 android:enabled="true"
 android:exported="true">
 <!--// 示意是否容许这个播送接收器接管本程序以外的播送 -->
 <intent-filter>
 <action android:name="ndroid.net.conn.CONNECTIVITY_CHANGE"/>
 <!-- 网络变动实现后收回一条播送 android.intent.action.BOOT_COMPLETED 的播送 -->
 </intent-filter>
</receiver>

动态注册一个自定义的播送。

<receiver android:name=".TestReceiver"
 android:enabled="true"
 android:exported="true">
 <!--// 示意是否容许这个播送接收器接管本程序以外的播送 -->
 <intent-filter>
 <action android:name="11"/>// 定义 action 为“11”</intent-filter>
</receiver>

// 形式 1
Intent intent=new Intent("11");
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){intent.setPackage(getPackageName());// 包名发送播送 com.soudao.test
}
sendBroadcast(intent);
// 形式 2
Intent intent=new Intent("11");
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
    // 该形式实用:给其余利用的播送接收者发送音讯(指定利用的包名、指定类的全类名)intent.setComponent(new ComponentName(getPackageName(), getPackageName()+".TestReceiver"));
 intent.setClassName(getPackageName(), getPackageName()+".TestReceiver");
}
sendBroadcast(intent);

后果:都调用到 onReceive()
D/TestReceiver: onReceive()

动静自定义播送

public class ReceActivity extends AppCompatActivity {
    private TestReceiver receiver;
 private IntentFilter intentFilter;
 private Button btn_b;
 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_rece);
 // 动静注册播送
 receiver=new TestReceiver();
 intentFilter=new IntentFilter();
 intentFilter.addAction("11");
 registerReceiver(receiver,intentFilter);// 注册播送
 Log.d("aa",getPackageName());
 
 // 点击按钮发送播送
 btn_b=findViewById(R.id.btn_b);
 btn_b.setOnClickListener(new View.OnClickListener() {
            @Override
 public void onClick(View v) {Intent intent=new Intent("11");
 sendBroadcast(intent);// 发送播送,这是一个无序的播送
 }
        });
 }
 
 @Override
protected void onDestroy() {super.onDestroy();
 unregisterReceiver(receiver);// 解除播送注册
}
}

动静发送有序播送,设置了优先级 Priority 属性(-1000-1000)

// 动静注册一个播送接收者 TestReceiver
receiver=new TestReceiver();
intentFilter=new IntentFilter();
intentFilter.addAction("11");
intentFilter.setPriority(200);
registerReceiver(receiver,intentFilter);
// 动静注册一个播送接收者 TestReceiver2
receiver2=new TestReceiver2();
intentFilter=new IntentFilter();
intentFilter.addAction("11");
intentFilter.setPriority(100);
registerReceiver(receiver2,intentFilter);
public class TestReceiver2 extends BroadcastReceiver {
    private static final String TAG="TestReceiver2";
 @Override
 public void onReceive(Context context, Intent intent) {Log.d(TAG,"我是 TestReceiver2 的 onReceive()");
 }

点击按钮发送播送

 Intent intent=new Intent("11");
sendOrderedBroadcast(intent,null);
后果:D/TestReceiver: onReceive()
D/TestReceiver2: 我是 TestReceiver2 的 onReceive()

如果咱们想拦挡播送
能够在 onReceive()中调用 abortBroadcast(); 即播送就不会再传递上来了

本地播送应用
业界常见的一些 减少安全性的计划 包含:
1. 对于同一 App 外部发送和接管播送,将 exported 属性人为设置成 false, 使得非本 App 外部收回的此播送不被接管
2. 在播送发送和接管时,都减少相应的 permission, 用于权限验证
3. 发送播送时,指定特定播送所在的包名,具体是通过 intent.setPackage(packageName) 指定,这样此播送将只会发送到此包中的 App 内与之相匹配的无效播送接收器中。
4. 采纳 LocalBroadcastManager 的形式
本地播送 LocalBroadcastManager 应用该机制收回的播送只可能在应用程序外部进行传递,并且播送接收器也只能接管来自本地应用程序收回的播送,这样所有的安全性问题都不存在了。

public class LocalReceiver  extends BroadcastReceiver {
    @Override
 public void onReceive(Context context, Intent intent) {Log.d("LocalReceiver","我是本地播送接收器");
 }
}
// 注册本地播送
LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);// 获取实例
LocalReceiver localReceiver=new LocalReceiver();
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("cccc");
localBroadcastManager.registerReceiver(localReceiver,intentFilter);// 注册本地播送监听

@Override
protected void onDestroy() {super.onDestroy();
 //unregisterReceiver(receiver);
 localBroadcastManager.unregisterReceiver(localReceiver);// 登记本地播送
}

发送本地播送

 Intent intent=new Intent("cccc");
localBroadcastManager.sendBroadcast(intent);// 发送本地播送
 //localBroadcastManager.sendBroadcastSync(intent);// 发送本地有序播送
 
 后果:D/LocalReceiver: 我是本地播送接收器

播送权限无关
动态注册的形式:

自定义播送权限
<uses-permission android:name="com.ruan.rocky.permission"/>
<permission
 android:name="com.ruan.rocky.permission"
 android:label="BroadcastReceiverPermission"
 android:protectionLevel="signature">
</permission>
//permission 的目录和 <application> 同级的地位配置应用到的权限
//protectionLevel="signature" 的属性有哪些://normal:默认的,利用装置前,用户能够看到相应的权限,但无需用户被动受权。//dangerous:normal 安全级别管制以外的任何危险操作。须要 dangerous 级别权限时,Android 会明确要求用户进行受权。常见的如:网络应用权限,相机应用权限及联系人信息应用权限等。//signature:它要求权限申明利用和权限应用利用应用雷同的 keystore 进行签名。如果应用同一 keystore,则该权限由零碎授予,否则零碎会回绝。并且权限授予时,不会告诉用户。它罕用于利用外部。** 把 protectionLevel 申明为 signature。如果别的利用应用的不是同一个签名文件,就没方法应用该权限,从而爱护了本人的接收者 **



<receiver android:name=".TestReceiver"
 android:enabled="true"
 android:exported="true"
 android:permission="com.ruan.rocky.permission">// 增加了一个自定义的权限
 <!--// 示意是否容许这个播送接收器接管本程序以外的播送 -->
 <intent-filter>
 <action android:name="11"/>
 </intent-filter>
</receiver>

动静注册权限

receiver=new TestReceiver();
intentFilter=new IntentFilter();
intentFilter.addAction("11");
//intentFilter.setPriority(200);
registerReceiver(receiver,intentFilter,"com.ruan.rocky.permission",null);

在注册的时候,最要害的一点是用 registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) 进行注册,而不是平时用的是 registerReceiver(BroadcastReceiver, IntentFilter)。相较于后者,前者在注册的时候要求了发送者必须具备的权限。如果发送者没有该权限,那么发送者发送的播送即便通过 IntentFilter 的过滤,也不会被 receiver 接管。此时如果再自定义一个权限,并且将权限的 protectionLevel 设置为 signature,那么内部利用便无奈应用该权限,也就无奈涉及到该 receiver。
发送播送:

Intent intent=new Intent("11");
sendBroadcast(intent,"com.ruan.rocky.permission");// 发送无序的权限 播送
//sendOrderedBroadcast(intent,"com.ruan.rocky.permission"); 发送有序的权限,播送

Android 播送机制
1. 同一 app 外部的同一组件内的音讯通信(单个或多个线程之间);
2. 同一 app 外部的不同组件之间的音讯通信(单个过程);
3. 同一 app 具备多个过程的不同组件之间的音讯通信;
4. 不同 app 之间的组件之间音讯通信;
5.Android 零碎在特定状况下与 App 之间的音讯通信
从实现原理上,Android 中的播送采纳了观察者模式,基于音讯的公布 / 订阅事件模型,因而,从实现的角度来看,Android 中的播送将播送的发送者和接收者极大水平的解耦,使得零碎能不便集成,更易扩大
1. 播送接收者 BroadcastReceiver 通过 Binder 机制向 AMS(Activity Manager Service) 进行注册;
2. 播送发送者通过 binder 机制向 AMS 发送播送;
3.AMS 查找合乎相应条件(IntentFilter/Permission 等)的 BroadcastReceiver,将播送发送到 BroadcastReceiver(个别状况下是 Activity)相应的音讯循环队列中;
4. 音讯循环执行拿到此播送,回调 BroadcastReceiver 中的 onReceive()办法
由此看来,播送发送者和播送接收者别离属于观察者模式中的音讯公布和订阅两端,AMS 属于两头的解决核心。播送发送者和播送接收者的执行是异步的,收回去的播送不会关怀有无接收者接管,也不确定接收者到底是何时能力接管到。显然,整体流程与 EventBus 十分相似。
在上文说列举的播送机制具体能够应用的场景中,现剖析理论利用中的适用性
第一种情景:同一 app 外部的同一组件内的音讯通信(单个或多个线程之间),理论利用中必定是不会用到播送机制的(尽管能够用),无论是应用扩大变量作用域、基于接口的回调还是 Handler-post/Handler-Message 等形式,都能够间接解决此类问题,若实用播送机制,显然有些“杀鸡牛刀”的感觉,会显太“重”;
第二种情景:同一 app 外部的不同组件之间的音讯通信(单个过程),对于此类需要,在有些教简单的状况下单纯的依附基于接口的回调等形式不好解决,此时能够间接应用 EventBus 等,相对而言,EventBus 因为是针对对立过程,用于解决此类需要非常适合,且轻松解耦。
第三、四、五情景:因为波及不同过程间的音讯通信,此时依据理论业务应用播送机制会显得十分合适
结尾:拨开云雾见天日 守得云开见月明

退出移动版