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因为是针对对立过程,用于解决此类需要非常适合,且轻松解耦。
第三、四、五情景:因为波及不同过程间的音讯通信,此时依据理论业务应用播送机制会显得十分合适
结尾:拨开云雾见天日 守得云开见月明