一、Android的广播主要主要可以分为两种类型:标准广播和有序广播。
1.标准广播
是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
2.有序广播
是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
二、接收系统广播
注册广播的方式一般有两种,在代码中注册和在AndroidManifest.xml中注册,其中前者也被称为动态注册,后者也被称为静态注册。
动态注册 通过代码的方式调用 registerReceiver 注册广播接收者 这个广播跟注册它的组件声明周期相关 只有注册这个广播的组件活着才能够收到广播,动态注册的广播接收者 在activity退出的时候要注销掉
静态注册 在清单文件中声明receiver节点 注册广播接收者 静态注册的广播即使应用没有启动 一样也可以收到广播
动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onCreate()方法中,那么有没有办法可以让程序在未启动的情况下就能接收到广播呢?这就需要使用静态注册的方式了。
创建广播接收器步骤:
①重写一个类 继承BroadcastReceiver
②重写父类的onReceive方法
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//当收到广播之后 就会调用onReceive方法
}
}
eg.动态注册监听网络变化
public class MainActivity extends AppCompatActivity{
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentfilter.addAction("android..net.conn.CONNECTIVITY_CHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver,intentFilter);
}
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectionManager.getActiveNerworkInfo();
if(networkInfo!=null&&networkInfo.isAvailable()){
Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();
}
}
}
}
获取网络状态需声明权限:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>;
eg.静态注册实现开机启动
public calss BootCompleteReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
Toast.makeText(context,"Boot Complete",Toast.LENGTH_SHORT).show();
}
}
静态的广播接收器一定要在AndroidManifest.xml文件中注册才可以使用
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETE"/>
</intent-filter>
</receiver>
另外,监听系统开机广播也是需要声明权限的:<uses-permission android:name=‘android.intent.action.RECEIVE_BOOT_COMPLETE"/>
注意:不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceive()方法运行了较长时间而没有结束时,程序就会报错。
三、发送自定义广播
1.发送标准广播
public class MyBroadcastReceiver enxtends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
}
}
在AndroidManifest.xml中注册
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent_filter>
</receiver>
在MainActivity中设置一按钮的监听事件,发送自定义广播:
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
}
}
这样我们就成功完成了发送自定义广播的功能。另外,由于广播时使用 Intent进行传递的,因此你还可以在Intent 中携带一些数据传递给广播接收器。
2.发送有序广播
广播时一种可以跨进程的通信方式,这一点从前面接收系统广播的时候就可以看出来了。因此我们应用程序内发出的广播,其他的应用程序应该也是可以收到的。
发送有序广播,我们重新回到BroadcastTest项目,然后修改MainActivity中的代码:
public class MainActivity extends AppcompatActivity{
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent,null);
});
...
}
...
}
可以看到发送有序广播只需要改动一行代码,即将sendBroadcast()方法改成sendOrderedBroadcast()方法。sendOrderedBroadcast()方法接收两个参数,第一个参数仍然是Intent,第二个参数是一个与权限相关的字符串,这里传入null就行了。
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
我们可以通过android:priority属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播。
既然已经获得了接收广播的优先权,那么MyBroadcastReceiver就可以选择是否允许广播继续传递了。
public class MyBroadcastReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
Toast.makeText(context,"received in MyBroadcastReceiver”,Toast.LENGTH_SHORT).show();
abortBroadcast();
}
}
如果在onReceive()方法中调用了abortBroadcast()方法,就表示将这条广播截断,后面的广播接收器将无法再接收到这条广播。
四、使用本地广播
前面我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播,这样很容易引起安全性的问题,比如说我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器李发送各种垃圾广播。
为了能够简单地解决广播地安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够再应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
本地广播,主要就是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
public class MainActivity extends AppCompatActivity{
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
private LocalBroadcastManager localBroadcastManager;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBraodcastManager = LocalBroadcastManager.getInstance(this);//获取实例
Button button = (Button) findViewById(R.id.button);
button.setOnClickListenter(new View.OnClickListener(){
Intent intent=new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
}
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver,intentFilter);//注册本地广播监听器
}
protected void onDestroy(){
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
class localReceiver extends BroadcastReceiver{
Toast.makeText(context,"received local broadcast",Toast.LENGTH_SHORT).show();
}
}
另外需要注意一点:本地广播是无法通过静态注册的方式来接收的。其他这也完全可以理解,因为静态注册主要就是为了让程序在未启动的情况下也能收到广播,而发送本地广播时,我们的程序肯定时已经启动的了。
本地广播几点优势:
发送的广播无法离开我们的程序,因此不必担心机密数据泄密。
其他程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患。
发送本地广播比发送系统全局广播将会更加高效。
不同版本广播的特点
4.0之后 关于广播 有如下更新
① 通过force stop停止的应用 不能收到广播
②没有运行过的应用不能收到广播(想要收到广播 必须在有界面的情况下运行一次 才能收到广播)
有序广播和无序广播
有序广播指定优先级 通过给intent-filter节点 指定一个priority 优先级 可以确定有序广播的接收顺序 priority最大值就是int类型的最大值
中断一个有序广播调用的方法 abortBroadcast();
如何判断一个广播是有序还是无序 就是看调用abortBroadcast() 是否会报错
如果是有序广播 可以调用abortBroadcast()
如果是无序的调用abortBroadcast()会报错
<receiver android:name="cn.dong.receiveorderbroadcast.FarmerReceiver">
<intent-filter android:priority="100">
<action android:name="cn.dong.sendrice"/>
</intent-filter>
</receiver>
发送广播的方法 接收广播的顺序 广播是否可以被中断
有序广播 sendOrderedBroadcast 可以指定优先级 按优先级接收 可以中断
无序广播 sendBroadcast(intent) 没有顺序 同时收到 不可以中断