• Android BroadCastReceiver介绍


    本文主要简单的讨论下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:

    <receiver android:name="com.xiaomo.view.broadcast.StaticReceiverTool">
    <intent-filter>
    <action android:name="com.xiaomo.view.broadcast01"></action>
    </intent-filter>
    </receiver>

    广播接收者可以接收系统自带的广播,也可以接收自定义的广播

    那么相应的,Intent中的action可以自定义也可以是使用系统相应服务特定的action

    自定义的广播发送方式一般如下:

    Intent intent = new Intent("com.xiaomo.view.broadcast01");
    sendBroadcast(intent);
    // sendBroadcast(intent);连续发送两次,那么接收者就会连续接收两次同样的广播


    对于多个广播接收者接收同一个广播,会涉及到优先级priority的概念,下面再定义一个broadcastReceiver(动态与静态的区别上面已经说过,这里采用静态的方式):

    复制代码
    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中得配置:

    <receiver android:name="com.xiaomo.view.broadcast.StaticReceiverTool02">
    <intent-filter android:priority="10">
    <action android:name="com.xiaomo.view.broadcast01"></action>
    </intent-filter>
    </receiver>

    注意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)

    。。。哈哈,好吧,我承认,这个我看了一眼,就没看过第二眼(当然也从来没见过哪里使用这种方式发送广播的....)

    转载自:android broadcastreceiver介绍

  • 相关阅读:
    NYOJ 260
    NYOJ 271
    [转载]《博客园精华集》Winform筛选结果(共105篇)
    在DataGridView控件中加入ComboBox下拉列表框的实现
    给SQL补充一个查看表结构的存储过程
    编写自定义控件之下拉式属性
    PropertyGrid中的枚举显示为中文(转)
    DataGridView 中合并单元格
    树TreeView控件与DataTable交互添加节点(最高效的方法)
    通过键盘方向键控制TreeView节点的移动
  • 原文地址:https://www.cnblogs.com/maydow/p/4740689.html
Copyright © 2020-2023  润新知