专栏首页AnRFDevAndroid 广播机制(Broadcast)介绍与使用

Android 广播机制(Broadcast)介绍与使用

Android应用可以通过广播从系统或其他App接收或发送消息。类似于订阅-发布设计模式。当某些事件发生时,可以发出广播。 系统在某些状态改变时会发出广播,例如开机、充电。App也可发送自定义广播。广播可用于应用间的通讯,是IPC的一种方式。

广播的种类

广播的种类也可以看成是广播的属性。

标准广播(Normal Broadcasts)

完全异步的广播。广播发出后,所有的广播接收器几乎同时接收到这条广播。 不同的App可以注册并接到标准广播。例如系统广播。

有序广播(Ordered Broadcasts)

同步广播。同一时刻只有一个广播接收器能接收到这条广播。这个接收器处理完后,广播才会继续传递。 有序广播是全局的广播。

本地广播(Local Broaddcasts)

只在本App发送和接收的广播。注册为本地广播的接收器无法收到标准广播。

带权限的广播

发送广播时可以带上相关权限,申请了权限的App或广播接收器才能收到相应的带权限的广播。 如果在manifest中申请了相应权限,接收器可以不用再申请一次权限即可接到相应广播。

接收广播

创建广播接收器,调用onReceive()方法,需要一个继承BroadcastReceiver的类。

注册广播

代码中注册称为动态注册。在AndroidManifest.xml中注册称为静态注册。动态注册的刚波接收器一定要取消注册。在onDestroy()方法中调用unregisterReceiver()方法来取消注册。

不要在onReceive()方法中添加过多的逻辑操作或耗时的操作。因为在广播接收器中不允许开启线程,当onReceive()方法运行较长时间而没结束时,程序会报错。因此广播接收器一般用来打开其他组件,比如创建一条状态栏通知或启动一个服务。

新建一个MyExampleReceiver继承自BroadcastReceiver。

public class MyExampleReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"Got it",Toast.LENGTH_SHORT).show();
        //abortBroadcast();
    }
}

abortBroadcast()可以截断有序广播

在AndroidManifest.xml中注册广播接收器;name里填接收器的名字。 可以设置广播接收器优先级:

<intent-filter android:priority="100">

<receiver android:name=".MyExampleReceiver">
    <intent-filter>
        <action android:name="com.rust.broadcasttest.MY_BROADCAST"/>
    </intent-filter>
</receiver>

让接收器接收到一条“com.rust.broadcasttest.MY_BROADCAST”广播。

发送自定义广播(标准广播)时,要传送这个值。例如:

Intent intent = new Intent("com.rust.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);

发送有序广播,应当调用sendOrderedBroadcast();

Intent intent = new Intent("com.rust.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent,null);

发送广播

App有3种发送广播的方式。发送广播需要使用Intent类。

sendOrderedBroadcast(Intent, String)

发送有序广播。每次只有1个广播接收器能接到广播。 接收器接到有序广播后,可以完全地截断广播,或者传递一些信息给下一个接收器。 有序广播的顺序可受android:priority标签影响。同等级的接收器收到广播的顺序是随机的。

sendBroadcast(Intent)

以一个未定义的顺序向所有接收器发送广播。也称作普通广播。 这种方式更高效,但是接收器不能给下一个接收器传递消息。这类广播也无法截断。

LocalBroadcastManager.sendBroadcast

广播只能在应用程序内部进行传递,并且广播接收器也只能接收到来自本应用程序发出的广播。 这个方法比全局广播更高效(不需要Interprocess communication,IPC),而且不需要担心其它App会收到你的广播以及其他安全问题。

广播与权限

发送带着权限的广播

当你调用sendBroadcast(Intent, String)sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)时,你可以指定一个权限。 接收器在manifest中申请了相应权限时才能收到这个广播。

例如发送一个带着权限的广播

sendBroadcast(new Intent("com.example.NOTIFY"),
              Manifest.permission.SEND_SMS);

接收广播的app必须注册相应的权限

<uses-permission android:name="android.permission.SEND_SMS"/>

当然也可以使用自定义permission。在manifest中使用permission标签

<permission android:name="custom_permission" />

添加后编译一下。即可调用Manifest.permission.custom_permission

接收带权限的广播

若注册广播接收器时申明了权限,那么只会接收到带着相应权限的广播。

在配置文件中声明权限,程序才能访问一些关键信息。 例如允许查询系统网络状态。

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- 机器开机广播 -->
<uses-permission android:name="android.permission.BOOT_COMPLETED">

如果没有申请权限,程序可能会意外关闭。

示例 - 使用标准广播,本地广播,带权限的广播,有序广播

发送和接收广播。分为发送和接收方2个App。

使用带权限的广播。系统权限与自定义权限。 使用权限需要在AndroidManifest.xml中声明。如果是自定义权限,需要先添加自定义权限。

<!-- 自定义的权限  给广播用 -->
<permission android:name="com.rust.permission_rust_1" />
<uses-permission android:name="com.rust.permission_rust_1" />

发送广播时带上权限声明。接收方(不论是否己方App)需要在AndroidManifest.xml中申请权限。

注册接收器时也需要声明权限。

发送不带权限的有序广播

private void sendStandardOrderBroadcast() {
    Intent intent = new Intent(MSG_PHONE);
    sendOrderedBroadcast(intent, null);
    Log.d(TAG, "[App1] 发送不带权限的有序广播, " + intent.getAction());
}

发送方App1代码

private static final String TAG = "rustApp";
public static final String MSG_PHONE = "msg_phone";
public static final String PERMISSION_RUST_1 = "com.rust.permission_rust_1";

    // 注册广播接收器
    registerReceiver(mStandardReceiver1, makeIF());
    registerReceiver(mStandardReceiver2, makeIF());
    registerReceiver(mStandardReceiver3, makeIF());

    registerReceiver(mStandardReceiverWithPermission, makeIF(),
            Manifest.permission.permission_rust_1, null);  // 带上权限

    LocalBroadcastManager.getInstance(getApplicationContext())
            .registerReceiver(mLocalReceiver1, makeIF());
    LocalBroadcastManager.getInstance(getApplicationContext())
            .registerReceiver(mLocalReceiver2, makeIF());
    LocalBroadcastManager.getInstance(getApplicationContext())
            .registerReceiver(mLocalReceiver3, makeIF());

    // 解除接收器
    unregisterReceiver(mStandardReceiver1);
    unregisterReceiver(mStandardReceiver2);
    unregisterReceiver(mStandardReceiver3);

    unregisterReceiver(mStandardReceiverWithPermission);

    LocalBroadcastManager.getInstance(getApplicationContext())
            .unregisterReceiver(mLocalReceiver1);
    LocalBroadcastManager.getInstance(getApplicationContext())
            .unregisterReceiver(mLocalReceiver2);
    LocalBroadcastManager.getInstance(getApplicationContext())
            .unregisterReceiver(mLocalReceiver3);


// 发送标准广播
private void sendStandardBroadcast() {
    Intent intent = new Intent(MSG_PHONE);
    sendBroadcast(intent);
    Log.d(TAG, "[App1] Dispatcher 发送标准广播");
}

// 发送带权限的标准广播
private void sendStandardBroadcastWithPermission() {
    Intent intent = new Intent(MSG_PHONE);
    sendBroadcast(intent, PERMISSION_RUST_1);
    Log.d(TAG, "[App1] Dispatcher 发送带权限的标准广播");
}

// 发送本地广播
private void sendAppLocalBroadcast() {
    Intent intent = new Intent(MSG_PHONE);
    LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
    Log.d(TAG, "[App1] Dispatcher 发送本地广播");
}

private IntentFilter makeIF() {
    IntentFilter intentFilter = new IntentFilter(MSG_PHONE);
    intentFilter.addAction(Intent.ACTION_TIME_TICK);
    intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
    return intentFilter;
}

// 标准接收器  用context来注册
private BroadcastReceiver mStandardReceiver1 = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 标准接收器1 收到: " + intent.getAction());
    }
};

// 标准接收器  用context来注册
private BroadcastReceiver mStandardReceiver2 = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 标准接收器2 收到: " + intent.getAction());
        if (intent.getAction().endsWith(MSG_PHONE)) {
            abortBroadcast(); // 截断有序广播
            Log.d(TAG, "[App1] 标准接收器2截断有序广播 " + intent.getAction());
        }
    }
};

// 标准接收器  用context来注册
private BroadcastReceiver mStandardReceiver3 = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 标准接收器3 收到: " + intent.getAction());
    }
};

// 注册的时候给它带权限  标准接收器
private BroadcastReceiver mStandardReceiverWithPermission = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 带权限的标准接收器收到: " + intent.getAction());
    }
};

/**
 * 用LocalBroadcastManager来注册成为本地接收器
 * 收不到标准广播 - 不论是本app发出的还是别的地方发出来的
 */
private BroadcastReceiver mLocalReceiver1 = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 本地接收器1 收到: " + intent.getAction());
    }
};

private BroadcastReceiver mLocalReceiver2 = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 本地接收器2 收到: " + intent.getAction());
    }
};

private BroadcastReceiver mLocalReceiver3 = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "[App1] 本地接收器3 收到: " + intent.getAction());
    }
};

接收方App2代码

<!-- 自定义的权限  给广播用 -->
<permission android:name="com.rust.permission_rust_1" />
<uses-permission android:name="com.rust.permission_rust_1" />
public static final String MSG_PHONE = "msg_phone";
        registerReceiver(mDefaultReceiver, makeIF());
        LocalBroadcastManager.getInstance(getApplicationContext())
                .registerReceiver(mLocalReceiver, makeIF());

        unregisterReceiver(mDefaultReceiver);
        LocalBroadcastManager.getInstance(getApplicationContext())
                .unregisterReceiver(mLocalReceiver);


    private BroadcastReceiver mDefaultReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "[App2] standard receive: " + intent.getAction());
        }
    };

    private BroadcastReceiver mLocalReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "[App2] local receive: " + intent.getAction());
        }
    };

    private IntentFilter makeIF() {
        IntentFilter intentFilter = new IntentFilter(MSG_PHONE);
        intentFilter.addAction(Intent.ACTION_TIME_TICK);
        intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
        return intentFilter;
    }

使用LocalBroadcastManager发出的本地广播,另一个App是接收不到的。

要收到本地广播,同样需要LocalBroadcastManager来注册接收器。

可以把本地广播看成是一个局部的,App内的广播体系。

实验中我们注意到,Intent.ACTION_TIME_TICK广播是可以截断的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android四大组件:BroadcastReceiver史上最全面解析

    BroadcastReceiver,本质上是一个全局的监听器,属于Android四大组件之一。

    Carson.Ho
  • Android 四大组件之BroadcastReceiver

    Hi,大家好,又双见面啦,上一期我们讲了如何使用Activity,肯定有不少小伙伴已经创建了属于自己的FirstActivity,那么这一期我们主要为大家介绍第...

    下码看花
  • Broadcast 使用详解

    本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

    用户1119350
  • Android应用实现安装后自启动的方法

    ACTION_PACKAGE_ADDED 一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)

    砸漏
  • 在Android中实现service动态更新UI界面

    之前曾介绍过Android的UI设计与后台线程交互,据Android API的介绍,service一般是在后台运行的,没有界面的。那么如何实现service动态...

    欢醉
  • Android中进程间通信(IPC)方式,知多少?

    小编在车机项目测试中,有很多的定制需求,需要系统或者第三方应用和车机应用进行通信,故针对此部分学习下,希望不再做测试小白。

    用户5521279
  • Android组件安全

    组件是一个Android程序至关重要的构建模块。Android有四种不同的应用程序组件:Activity、Service、Content Provider和Br...

    信安之路
  • Android四大组件详解

    Android四大组件分别为activity、service、content provider、broadcast receiver。

    用户7557625
  • Android基于AlarmManager实现用户在线心跳功能示例

    本文实例讲述了Android基于AlarmManager实现用户在线心跳功能。分享给大家供大家参考,具体如下:

    砸漏
  • Android Intents and Intent Filters(一)

    看过前面的几节教程的应该都会留意到一个很重要的东西,那就是Intent。Intent是什么呢?我们都知道Android有四大核心组件 Activity、Serv...

    飞雪无情
  • Android学习笔记(一)Android应用程序的组成部分

      Android应用程序由松散耦合的组件组成,并使用应用程序Manifest绑定到一起;应用程序Manifest描述了每一组件和它们之间的交互方式,还用于指定...

    codingblock
  • Android开发笔记(四十二)Broadcast的生命周期

    广播(Broadcast)用于Android组件之间的灵活通信,它与Activity和Service的区别在于: 1、Activity和Service都只...

    用户4464237
  • 咦,Oreo怎么收不到广播了?

    菜天哥哥
  • Android:BroadcastRecevicer广播类型汇总

    注:当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播

    Carson.Ho
  • Android手机App安全漏洞整理(小结)

    当前APK文件的安全性是非常令人堪忧的。APK运行环境依赖的文件/文件夹 res、DEX、主配文件Lib 只有简单的加密或者甚至没有任何加密。诸如apktool...

    砸漏
  • android开发(十九) BroadcastReceiver应用详解

    本文源自:http://blog.csdn.net/liuhe688/article/details/6955668

    Java架构师必看
  • Android开发入门的正确姿势

    对于从事移动客户端开发者的初学者而言,不论是Android还是iOS开发,对客户端开发有一个整体的认识,然后再逐步深入,这样会有事半功倍的效果。

    刘宁
  • Android必知必会的四大组件--Broadcast Receiver

    广播,在我们的应用中起着一个非常重要的角色。就比如说我们经常使用的Intent、IntentFilter,就有着广播的作用。

    ClericYi
  • C# Xamarin移动开发基础进修篇

    跟着阿笨一起玩NET

扫码关注云+社区

领取腾讯云代金券