zoukankan      html  css  js  c++  java
  • Android查缺补漏--BroadcastReceiver的类型与使用

    Broadcast 是一种被用于应用内和应用之间传递信息的机制。一个广播可以对应多个接受者。一个完整的广播机制,需要具有以下三个要素:

    • 发送广播的Broadcast
    • 接受广播的BroadcastReceiver
    • 传递信息的Intent

    广播的注册分为静态注册和动态注册:

    • 静态注册:静态注册的广播是指在AndroidManifest中注册的广播,此种广播在应用安装时就被系统解析,不需要启动应用就可以收到相应的广播。
    <receiver android:name=".broadcast.MyBroadcastReceiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    • 动态注册:通过Context.registerReceiver()来实现,不需要时要通过Context.unRegisterReceiver()解除广播,此种广播必须应用启动后才能注册并接收广播。
    // 动态注册广播接收器
    registerReceiver(new DynamicBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
    

    广播又分为普通广播、有序广播、本地广播和sticky广播。

    一、普通广播

    普通广播通过Context.sendBroadcast()发送,我们没有办法制定Receiver们对于普通广播的接收顺序。理论上所有的接收器(Receiver)接收到广播的顺序不确定,但一般是按照其在AndroidMainfest.xml文件中注册的顺序(不绝对)。
    普通广播中,接受者不能将处理结果传递给下一个接收器,也无法终止广播的传播。

    如下代码是一个静态注册的广播示例:

    public class MyBroadcastReceiver extends BroadcastReceiver {
    
        String TAG = MyBroadcastReceiver.class.getSimpleName();
    
        public static final String ACTION = "MY_BROADCAST_RECEIVER";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
        }
    }
    

    然后再AndroidMainfest.xml中注册这个广播:

    <receiver android:name=".broadcast.MyBroadcastReceiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    

    接下来在Activity中调用Context.sendBroadcast()发送广播就可以了:

    Intent intent = new Intent(MyBroadcastReceiver.ACTION);
    intent.putExtra(INTENT_INFO, "我是一个普通广播");
    sendBroadcast(intent);
    

    log如下:

    12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个普通广播
    
    • 普通广播的接收顺序测试
      我们仿照MyBroadcastReciver创建多个接收器,代码一样:
    /**
     * 静态注册的广播接收器2
     * Created by liuwei on 17/12/7.
     */
    public class MyBroadcast2Receiver extends BroadcastReceiver {
    
        String TAG = MyBroadcast2Receiver.class.getSimpleName();
    
        public static final String ACTION = "MY_BROADCAST_RECEIVER";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
        }
    }
    /**
     * 静态注册的广播接收器3
     * Created by liuwei on 17/12/7.
     */
    public class MyBroadcast3Receiver extends BroadcastReceiver {...}
    /**
     * 静态注册的广播接收器4
     * Created by liuwei on 17/12/7.
     */
    public class MyBroadcast4Receiver extends BroadcastReceiver {...}
    /**
     * 静态注册的广播接收器5
     * Created by liuwei on 17/12/7.
     */
    public class MyBroadcast5Receiver extends BroadcastReceiver {...}
    /**
     * 静态注册的广播接收器6
     * Created by liuwei on 17/12/7.
     */
    public class MyBroadcast6Receiver extends BroadcastReceiver {...}
    

    然后在AndroidMainfest.xml中为以上广播都注册同一个action

    <receiver android:name=".broadcast.MyBroadcastReceiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast6Receiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast2Receiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast3Receiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast4Receiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast5Receiver">
        <intent-filter>
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    

    点击发送广播,查看log:

    12-08 17:29:44.259 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个普通广播
    12-08 17:29:44.268 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个普通广播
    12-08 17:29:44.271 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个普通广播
    12-08 17:29:44.273 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个普通广播
    12-08 17:29:44.277 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个普通广播
    12-08 17:29:44.280 6644-6644/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个普通广播
    

    二、有序广播

    在AndroidMainfest.xml中注册广播时通过priority(值越优先级越高)节点为广播添加优先级,然后再用Context.sendOrderedBroadcast()发送,接收者们就会按照优先级顺序依次执行。

    有序广播的接收者和给下一个接收者传递数据,并且接收者在收到广播之后可以抛弃广播,使广播不再向后传递。

    为上面6个接收器添加优先级:

    <receiver android:name=".broadcast.MyBroadcastReceiver">
        <intent-filter android:priority="1">
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast6Receiver">
        <intent-filter android:priority="6">
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast2Receiver">
        <intent-filter android:priority="2">
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast3Receiver">
        <intent-filter android:priority="3">
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast4Receiver">
        <intent-filter android:priority="4">
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    
    <receiver android:name=".broadcast.MyBroadcast5Receiver">
        <intent-filter android:priority="5">
            <action android:name="MY_BROADCAST_RECEIVER" />
        </intent-filter>
    </receiver>
    

    然后通过sendOrderedBroadcast发送广播观察log:

    intent = new Intent(MyBroadcastReceiver.ACTION);
    intent.putExtra(INTENT_INFO, "我是一个有序广播");
    sendOrderedBroadcast(intent, null);
    

    log如下:

    12-08 18:17:26.455 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:17:26.462 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:17:26.464 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:17:26.465 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:17:26.466 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:17:26.467 25919-25919/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个有序广播
    
    • abortBroadcast()抛弃广播:
      普通的广播是没有办法抛弃的,否则会抛出RuntimeException的异常。

    只有有序广播才可以通过此方法抛弃。我们在MyBroadcast6Receiver中添加abortBroadcast()方法:

    public class MyBroadcast6Receiver extends BroadcastReceiver {
    
        String TAG = MyBroadcast6Receiver.class.getSimpleName();
    
        public static final String ACTION = "MY_BROADCAST_RECEIVER";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
            abortBroadcast();
            Log.i(TAG, "丢弃广播");
        }
    }
    

    然后点击发送有序广播,log如下:

    12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:34:27.989 1329-1329/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 丢弃广播
    

    可以看到广播已经被丢弃了。

    • setResult()传递给下一个接收者结果。
    • getResult()接收上一个接收者的结果。

    在MyBroadcast6Receiver中添加setResult方法,在MyBroadcast5Receiver添加getResult方法:

    public class MyBroadcast6Receiver extends BroadcastReceiver {
    
        String TAG = MyBroadcast6Receiver.class.getSimpleName();
    
        public static final String ACTION = "MY_BROADCAST_RECEIVER";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
    //        abortBroadcast();
    //        Log.i(TAG, "丢弃广播");
            setResult(006, "我是老6传来的消息", null);
        }
    }
    public class MyBroadcast5Receiver extends BroadcastReceiver {
    
        String TAG = MyBroadcast5Receiver.class.getSimpleName();
    
        public static final String ACTION = "MY_BROADCAST_RECEIVER";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "接收到广播消息:" + intent.getStringExtra(BroadcastTestActivity.INTENT_INFO));
            String data = getResultData();
            Log.i(TAG, "data=" + data);
        }
    }
    

    log如下:

    12-08 18:40:01.415 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast6Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:40:01.434 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast5Receiver: data=我是老6传来的消息
    12-08 18:40:01.440 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast4Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:40:01.442 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast3Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:40:01.445 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个有序广播
    12-08 18:40:01.447 10372-10372/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个有序广播
    

    三、本地广播

    以上的广播对于系统来说是全局的,发出广播后,系统内的应用只要注册了相应的接收器就都可以收到广播。如果我们想在本应用发出的广播只在此应用内可以收到,那么可以使用本地广播了。

    本地广播由 LocalBroadcastManager 管理,是在 API 21 以后添加的,使用起来也很方便,需要先通过 LocalBroadcastManager.getInstance() 方法获取其单例,剩下的用法与其他广播类似,其主要方法有以下几个:

    • registerReceiver():注册广播接收器。
    • unregisterReceiver():解除广播接收器。
    • sendBroadcast():发送异步广播。
    • sendBroadcastSync():发送同步广播。

    使用本地广播时,无需在AndroidMainfest.xml中注册,必须使用 LocalBroadcastManager.getInstance(...).registerReceiver(..)来注册接收器。

    我们来写个本地广播的小栗子,首先注册两个本地广播:

    LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcastReceiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
    LocalBroadcastManager.getInstance(context).registerReceiver(new MyBroadcast2Receiver(), new IntentFilter(MyBroadcastReceiver.ACTION));
    

    然后发送本地广播:

    intent.putExtra(INTENT_INFO, "我是一个本地广播");
    LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
    

    log如下:

    12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcastReceiver: 接收到广播消息:我是一个本地广播
    12-09 17:20:47.799 15019-15019/cn.codingblock.androidadvancestudy I/MyBroadcast2Receiver: 接收到广播消息:我是一个本地广播
    

    四、sticky广播(不建议使用)

    sticky广播会一直处于滞留状态,sticky广播被发出后,只要有能够匹配其的新接收器被注册了就可以收到广播,sticky广播通过Context.sendStickyBroadcast()发送。


    最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!

    参考文献:

    • 《Android开发艺术探索》
    • 《Android开发进阶从小工到专家》
  • 相关阅读:
    Oracle中有大量的sniped会话
    Error 1130: Host '127.0.0.1' is not allowed to connect to this MySQL server
    汉字转换为拼音以及缩写(javascript)
    高效率随机删除数据(不重复)
    vs2010 舒服背景 优雅字体 配置
    mvc中的ViewData用到webfrom中去
    jquery ajax return值 没有返回 的解决方法
    zShowBox (图片放大展示jquery版 兼容性好)
    动感效果的TAB选项卡 jquery 插件
    loading 加载提示······
  • 原文地址:https://www.cnblogs.com/codingblock/p/8034110.html
Copyright © 2011-2022 走看看