一、广播机制简介
1.Android中每个应用都可以对自己感兴趣的广播进行注册,监听。这些广播可以是系统的,也可以来自其他程序。
2.广播的类型:
- 有序广播 : 是一种同步的广播,在广播发出后,同一时刻只有一个广播接收器可以收到广播,并且等待这个接收器,处理完成逻辑后,广播才会继续。所以这样广播接收器就有了优先级的划分,优先级高的自然能够首先获取广播信息 。优先级别的设置可以通过属性
<intent-filter android:priority="1000">
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
- 标准广播 : 是一种完全异步的广播,在广播发出后,所有的广播接收几乎 可以同时获取到广播的信息,他们之间没有优先级别之分。
二、接收系统广播
Android中内置了很多系统级别的广播,我们可以在应用中通过监听这些广播来得到系统的信息。例如获取手机开机信息 ,获取手机网络信息等。其中我们需要在应用中注册自己的广播接收器,注册广播接收有两种方法
1.动态注册:通过代码在适当的位置进行广播接收器的注册,以及广播接收的注销注册。首先创建IntentFilter实例,并且设置其Action ,因为系统的每个广播发出都会带有action值。例如设备的网络发生变化的时候就会发出一条action值为 :”android.net.conn.CONNECTIVITY_CHANGE” 的广播。接着就是通过 registerReceiver(broadcastReceiver,filter)来注册广播接收器
IntentFilter filter = new IntentFilter( );
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
netWorkChangeReceiver = new NetWorkChangeReceiver() ;
registerReceiver(netWorkChangeReceiver ,filter) ;
Log.i("onCreate","注册广播接收器");
unregisterReceiver(netWorkChangeReceiver);
动态注册广播可以自由地控制注册与注销,在灵活方面有很大的优势,但是它存在一个缺点,就是必须在程序启动后才能接收到广播。
2.静态注册:解决了动态注册的缺点,可以在程序安装的时候就完成注册,并且进行监听广播。首先创建 继承 BroadcastReceiver的实例 ,并且重写其中 onReceive() 方法 (注意在onReceive()方法中不能做过多耗时的操作) 。接着需要我们在AndroidManifest.xml中进行注册该广播接收器。具体代码如下:
public class MyReceiver extends BroadcastReceiver {
private static final String PARAMES = "parames" ;
public MyReceiver() {
Log.i("BroadcastDemo ","myReceiver() ");
}
/**
* 发送自定义 ,标准广播
* @param context
* @param parames
*/
public static void sendBroadcast(Context context,String parames){
Intent intent = new Intent("com.example.chf.broadcast_test") ;
intent.putExtra(PARAMES ,parames) ;
context.sendBroadcast(intent);
}
/**
* 发送本地广播
* 本地广播接收器,只能通过动态注册,因为本地广播是在程序启动之后才会
* 去接收的
* @param context
* @param parames
*/
public static void sendLocalBroadcast(Context context ,String parames){
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context) ;
//动态注册 本地广播接收器
IntentFilter filter = new IntentFilter("com.example.chf.broadcast_test") ;
MyReceiver myReceiver = new MyReceiver() ;
localBroadcastManager.registerReceiver(myReceiver,filter);
Intent intent = new Intent("com.example.chf.broadcast_test") ;
intent.putExtra(PARAMES ,parames) ;
localBroadcastManager.sendBroadcast(intent);
}
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null ){
String parames = intent.getStringExtra(PARAMES) ;
Toast.makeText(context,parames,Toast.LENGTH_SHORT).show();
Log.i("接收广播信息",parames) ;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.chf.thefirstlinecodeofandroid">
.....
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter android:priority="100">
<action android:name="com.example.chf.broadcast_test"/>
</intent-filter>
</receiver>
</application>
</manifest>
AndroidManifest.xml中属性设置 android:enable 以及android:exported的作用。
* android:enabled =”true” : 在程序安装后系统就会自动实例化广播接收器
* android:enabled =”false”: 程序安装后系统不会自动实例化广播接收器。
* android:exported =”true’ 允许广播接收器接收来自外部应用程序的广播
* android:exported =”false” 不允许广播接收器接收来自外部的应用程序的广播
参看http://developer.android.com/intl/zh-cn/guide/topics/manifest/receiver-element.html
发现了一个有趣的问题:当我创建一个获取网络状态的广播接收器的时候,并且把该广播接收器设置为静态注册,但是程序退出后,无论如何改变当前的网络状态都无法获取到广播信息。但是如果是自定义的广播接收器,并且进行了静态注册,即使程序处于退出的状态,也还是可以获取到自定义的广播信息。
主要原因:
Android 3.1开始系统在Intent与广播相关中为每一个Intent设置了 flag参数 ,分别是:
* FLAG_INCLUDE_STOPPED_PACKAGES (包含已经停止的包)
* FLAG_EXCLUDE_STOPPED_PACKAGES(不包含已经停止的包)
自Android3.1系统开始,系统本身会增加多所有的app当前是否处于运行状态的跟踪。在发送广播的时候,不管是什么广播类型,系统默认为其设置的flag值为 FLAG_EXCLUDE_STOPPED_PACKAGES ,导致即使是静态注册的广播接收器,如果app处于进程退出的状态,将不能收到广播
参看http://developer.android.com/about/versions/android-3.1.html#launchcontrols
对于自定义的广播,我们可以通过设置Intent的Flag值为 FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的广播接收器,即使在App退出的情况下,也可以接收广播,并且会启动进程,但是此时的广播接收器会重新创建。
三、发送自定义广播
1.发送标准广播
Intent intent = new Intent("com.example.chf.broadcast_test") ;
intent.putExtra(PARAMES ,parames) ;
context.sendBroadcast(intent);
2.发送有序广播
通过 sendOrderedBroadcast(Intent intent ,String receiverPermission)发送有序广播。广播接收器 android:priority=”” 属性值越大接收广播的优先级越高,优先级较低的广播接收器只能等待优先级高的处理完逻辑后才能接收广播。但是优先级高的广播接收器,可以通过 abortBroadcast() 方法截断广播这样接下来的广播接收器就不可以接收到信息。同时优先级高的也可以通过 setResultData() 等方法 重新设置广播内容,这样在接下来的广播接收器通过 getResultData() 将会获取不一样的信息
public class MyReceiver extends BroadcastReceiver {
private static final String PARAMES = "parames" ;
public MyReceiver() {
Log.i("BroadcastDemo ","myReceiver() ");
}
......
/**
* 发送有序广播
* @param context
* @param parames
*/
public static void sendOrderedBroadcast(Context context ,String parames){
Intent intent = new Intent("com.example.chf.broadcast_test") ;
intent.putExtra(PARAMES ,parames) ;
context.sendOrderedBroadcast(intent,null);
}
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null ){
String parames = intent.getStringExtra(PARAMES) ;
Toast.makeText(context,parames,Toast.LENGTH_SHORT).show();
Log.i("接收广播信息","MyReceiver"+parames) ;
//abortBroadcast();
setResultData("从myReceiver()中修改后发出广播");
}
}
}
public class SecondReceiver extends BroadcastReceiver {
public SecondReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
String parames = getResultData() ;
Log.i("接收广播信息","SecondReceiver"+parames) ;
}
}
配置AndroidManifest.xml ,并且设置属性优先级
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.chf.thefirstlinecodeofandroid">
......
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.chf.broadcast_test" />
</intent-filter>
</receiver>
<receiver
android:name=".SecondReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="90">
<action android:name="com.example.chf.broadcast_test" />
</intent-filter>
</receiver>
</application>
</manifest>
测试结果就是
四、使用本地广播
通过获取LocalBroadcastManager ,通过其发送 sendBroadcast(intent)的方式发送本地广播,并且本地广播只允许动态注册。
本地广播优势:
* 1.不必担心本应用发送的广播信息会被其他应用所获取,保证了数据的安全性
* 2.其他应用不可能随意发送广播,使得应用本地广播接收器接收,所以你不必担心它们会被利用
* 3.比系统发送的全局广播更见高效
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context) ;
//动态注册 本地广播接收器
IntentFilter filter = new IntentFilter("com.example.chf.broadcast_test") ;
MyReceiver myReceiver = new MyReceiver() ;
localBroadcastManager.registerReceiver(myReceiver,filter);
Intent intent = new Intent("com.example.chf.broadcast_test") ;
intent.putExtra(PARAMES ,parames) ;
localBroadcastManager.sendBroadcast(intent);
注意动态广播只能是通过动态注册的方式 ,并且都要使用LoaclBroadcastManager来进行注册与发送。
Ps:小弟不才,文中难免会有些漏洞,仅作为笔记用途。如果哪里有严重错误欢迎大家留言,助我改进。同时大家也可以交个朋友。