本文主要简单的讨论下Android中广播发送与注册的多种方式
注册广播接收者有两种方式,动态与静态:
1,动态注册:在Activity的onCreate方法中或根据需要调用register()方法注册即可动态注册一个广播接收者,在代码中有关于其特点的简单注释,如下
private void register() { ReceiverTool rt = new ReceiverTool(); IntentFilter filter = new IntentFilter(); filter.addAction("com.xiaomo.view.broadcast01"); registerReceiver(rt, filter); } /** * 动态注册 -- 接收广播 * 每次接收广播使用的是同一个接收实例,并不会每次都创建一个实例 * @author Administrator * */ class ReceiverTool extends BroadcastReceiver { public ReceiverTool () { // Log.i(Constant.TAG, "创建了ReceiverTool的一个实例"); } @Override public void onReceive(Context context, Intent intent) { Log.i(Constant.TAG, "" + this.hashCode()); Log.i(Constant.TAG, "接到到广播, ACTION = " + intent.getAction()); } }
2,静态注册,自定义一个class extends BroadcastReceiver,然后在mainfest.xml中使用<receiver...>标签的形式注册,特性同样注释在代码中:
/** * 静态注册(mainfest.xml) -- 接收广播 * 每次接收到相应的广播,都会创建一个接收器的实例,这一点与动态注册不同 * 之所以这样设计,个人认为实属无奈,因为在mainfest.xml中注册了一个接收者,相当于一个标记 * 但系统无法知道什么时候会接收到对应的广播 * 1,系统在扫描到配置文件中注册了接收者时,就为其创建对象 (不知道什么时候会接收到广播) * 2,系统在该接收者接收到广播时,第一次为其创建对象 (不知道什么时候会再次接收到广播) * 如果这两种情况下,都在内存中保存这个接收者对象,那么就会出现对应的括号中场景 * 并且一直保存在内存中,明显占内存,浪费内存资源(一个接收者无关紧要,但若一个应用中有10, 100..个静态广播接收者,你懂的!) * 所以不能采用这样的设计,而采用每次接收到广播,就为其创建对象,用完就清掉 * 而且在处理接收广播过程中,Android还加上了超时限制(ANR异常,因为BroadcastReceiver默认运行在UI主线程中) * @author Administrator * */ public class StaticReceiverTool extends BroadcastReceiver{ public StaticReceiverTool() { // Log.i(Constant.TAG, "创建了StaticReceiverTool的一个实例"); } @Override public void onReceive(Context context, Intent intent) { // Log.i(Constant.TAG, "" + this.hashCode()); Log.i(Constant.TAG, "StaticReceiverTool接到到广播, ACTION = " + intent.getAction()); } }
mainfest.xml:
广播接收者可以接收系统自带的广播,也可以接收自定义的广播
那么相应的,Intent中的action可以自定义也可以是使用系统相应服务特定的action
自定义的广播发送方式一般如下:
Intent intent = new Intent("com.xiaomo.view.broadcast01"); sendBroadcast(intent); // sendBroadcast(intent);连续发送两次,那么接收者就会连续接收两次同样的广播
public class StaticReceiverTool02 extends BroadcastReceiver { public StaticReceiverTool02() { } @Override public void onReceive(Context context, Intent intent) { Log.i(Constant.TAG, "StaticReceiverTool02接到到广播, ACTION = " + intent.getAction()); // 接收non-ordered广播时,如果调用方法终止广播 // 会报异常:BroadcastReceiver trying to return result during a non-ordered // broadcast // this.abortBroadcast(); }
其对应的xml中得配置:
注意StaticReceiverTool02这个receiver的配置中加了优先级android:priority="10",那么使用上面的代码发送广播后,Log中的状态为:
StaticReceiverTool02接到到广播, ACTION = com.xiaomo.view.broadcast01
StaticReceiverTool接到到广播, ACTION = com.xiaomo.view.broadcast01
因为StaticReceiverTool02的优先级priority = 10 比StaticReceiverTool的0高(如果不加优先级设置,两者几乎同时收到广播,没有固定的顺序)
在android系统中默认的优先级 = 0, 优先级的范围为-1000 ~ 1000,最高的优先级为1000.
如果想终止广播,可以调用abortBroadcast();方法,但上面的示例中无论在哪个接收者中调用,都会出现异常(见code注释),这涉及到android系统中几种不同的广播发送方式,而若使用上面代码中的发送方式sendBroadcast(intent),则接收者在处理过程中是不能终止广播的继续传递的,这个在源码中明确说明。
接下来讨论下广播的几种发送方式:
1, 就是上面说到的常用方式:sendBroadcast(intent);
2, 有序广播 sendOrderedBroadcast(intent, "com.xiaomo"); (有序的广播可以使用abortBroadcast()终止广播)第二个参数为权限控制,无权限就写null即可
当然若加了权限,则必须在maifest.xml中申明权限且设置接收权限
<uses-permission android:name="com.xiaomo" />
<permission android:name="com.xiaomo" android:protectionLevel="normal"></permission>
这样才可以接收到广播,此时若在StaticReceiverTool02的onReceiver()中加入代码this.abortBroadcast();
那么StaticReceiverTool就接收不到这个广播了.
3,sendStickyBroadcast(intent);
这个不涉及到自定义权限,但是需要在配置文件中设置使用权限:<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
这种方式也同样不能在接收过程中,终止广播.
这种方式的特殊之处在于,广播发送出去后,即使没有对应的接收者,内存中也会缓存这个广播,在未删除之前,一旦有相应的接收者注册,那么这个接收者就会收到这个广播
还使用上面的例子,把action改一下即可(此段代码在activity的oncreate(...)中):
new Handler().postDelayed(new Runnable() { @Override public void run() { register(); } }, 30000); // new Handler().postDelayed(new Runnable() { // @Override // public void run() { // // register(); // } // }, 20000); Button button = (Button) findViewById(R.id.button1); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("com.xiaomo.view.broadcast02"); sendStickyBroadcast(intent); Log.i(Constant.TAG, "广播发送完毕"); } });
把上面register()方法中action的string值改成对应的02(额,主要是不想动配置文件了,不然好几个接收者接收同一个广播,对比的不清楚)
filter.addAction("com.xiaomo.view.broadcast02");
运行后,先点击button发送广播,可以发现log中只显示了“广播发送完毕”,等待大约30秒后,会显示“接收到广播。。。。”
即通过sendStickyBroadcast(intent)发送的广播先缓存在内存中,30秒后子线程执行注册广播接收者的代码,然后这个接收者就会立即接收到...broadcast02这个广播
当然也可以从内存中将这个缓存的广播删除:
@Override public void onReceive(Context context, Intent intent) { removeStickyBroadcast(intent);//删除在内存中的广播 Log.i(Constant.TAG, "" + this.hashCode()); Log.i(Constant.TAG, "接到到广播, ACTION = " + intent.getAction()); }
这样其他可以接收到这个广播的接收者就不会接收到这个广播了(当然当前的receiver得比其他receiver先接收到这个广播, 顺序问题又涉及到上面的有序/无序,优先级的问题了)
4,还有一种比较蛋疼的方式:sendStickyOrderedBroadcast(Intent intent,
BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,Bundle initialExtras)。。。哈哈,好吧,我承认,这个我看了一眼,就没看过第二眼(当然也从来没见过哪里使用这种方式发送广播的....)
转载自: