Android 广播 - 显式广播与隐式广播

测试引入

1、Receiver
java 复制代码
public class ExplicitAndImplicitReceiver extends BroadcastReceiver {

    public static final String TAG = ExplicitAndImplicitReceiver.class.getSimpleName();
    public static final String ACTION = "broadcast.ExplicitAndImplicitReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive start");

        if (intent == null) {
            Log.i(TAG, "intent is null");
            return;
        }
        String action = intent.getAction();
        if (action == null) {
            Log.i(TAG, "action is null");
            return;
        }
        if (!action.equals(ACTION)) {
            Log.i(TAG, "action is not " + ACTION);
            return;
        }

        Log.i(TAG, "onReceive finish");
    }
}
2、Activity
  • activity_explicit_and_implicit_receiver_test.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ExplicitAndImplicitReceiverTestActivity">

    <Button
        android:id="@+id/btn_send_explicit_broadcast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送显式广播"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_send_implicit_broadcast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送隐式广播"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_send_explicit_broadcast" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • ExplicitAndImplicitReceiverTestActivity.java
java 复制代码
public class ExplicitAndImplicitReceiverTestActivity extends AppCompatActivity {

    public static final String TAG = ExplicitAndImplicitReceiverTestActivity.class.getSimpleName();

    private Button btnSendExplicitBroadcast;
    private Button btnSendImplicitBroadcast;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_explicit_and_implicit_receiver_test);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        btnSendExplicitBroadcast = findViewById(R.id.btn_send_explicit_broadcast);
        btnSendImplicitBroadcast = findViewById(R.id.btn_send_implicit_broadcast);

        btnSendExplicitBroadcast.setOnClickListener(v -> {
            Log.i(TAG, "发送显式广播");
            Intent intent = new Intent(this, ExplicitAndImplicitReceiver.class);
            sendBroadcast(intent);
        });

        btnSendImplicitBroadcast.setOnClickListener(v -> {
            Log.i(TAG, "发送隐式广播");
            Intent intent = new Intent(ExplicitAndImplicitReceiver.ACTION);
            sendBroadcast(intent);
        });
    }
}
3、Test
(1)不声明 receiver
  1. 发送显式广播,输出结果

    发送显式广播

  2. 发送隐式广播,输出结果

    发送隐式广播

(2)声明 receiver,不声明 intent-filter
xml 复制代码
<receiver
    android:name=".mybroadcast.ExplicitAndImplicitReceiver"
    android:exported="false" />
  1. 发送显式广播,输出结果

    发送显式广播
    onReceive start
    action is null

  2. 发送隐式广播,输出结果

    发送隐式广播

(3)声明 receiver,声明 intent-filter(匹配的 action)
  1. 发送显式广播,输出结果

    发送显式广播
    onReceive start
    action is null

  2. 发送隐式广播,输出结果

    理想情况

    发送隐式广播
    onReceive start
    onReceive finish

    实际情况

    发送隐式广播

(4)声明 receiver,声明 intent-filter(不匹配的 action)
  1. 发送显式广播,输出结果

    发送显式广播
    onReceive start
    action is null

  2. 发送隐式广播,输出结果

    理想情况

    发送隐式广播
    onReceive start
    action is not broadcast.ExplicitAndImplicitReceiver

    实际情况

    发送隐式广播


测试结果分析

1、小结
测试 Receiver intent-filter 显式广播结果 隐式广播结果 原因
1 收不到 收不到 未注册 Receiver
2 收到 收不到 隐式广播在 Android 8.0+ 被限制
3 有,匹配的 action 收到 收不到 隐式广播在 Android 8.0+ 被限制
4 有,不匹配的 action 收到 收不到 隐式广播在 Android 8.0+ 被限制
  1. 静态注册的 Receiver 使用显式广播

  2. 可以不加 intent-filter(加不加都可以收到)

  3. Receiver 内可以不检查 action,直接接收广播

  4. 如果要检查 action(区分多个 action),显式广播的 Intent 中需要包含 action

2、实践
java 复制代码
public class ExplicitAndImplicitReceiver extends BroadcastReceiver {

    public static final String TAG = ExplicitAndImplicitReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive start");

        ...

        Log.i(TAG, "onReceive finish");
    }
}
xml 复制代码
<receiver
    android:name=".mybroadcast.ExplicitAndImplicitReceiver"
    android:exported="false" />
java 复制代码
Log.i(TAG, "发送显式广播");
Intent intent = new Intent(this, ExplicitAndImplicitReceiver.class);
sendBroadcast(intent);

显式广播与隐式广播

- 显式广播 隐式广播
目标指定 明确指定接收者类名 不指定接收者,通过 IntentFilter 匹配
接收范围 只能被指定的接收者接收 可以被多个接收者接收
安全系数 较高,只能被指定接收者接收 较低,可能被其他应用接收
应用场景 应用内组件通信 系统广播、跨应用通信

Android 8.0+ 对隐式广播的限制

  1. 从 Android 8.0(API 26)开始,静态注册的广播接收器无法接收大多数隐式广播

  2. 除非是豁免的广播,例如,系统广播


动态注册测试

1、Receiver
java 复制代码
public class ExplicitAndImplicitReceiver extends BroadcastReceiver {

    public static final String TAG = ExplicitAndImplicitReceiver.class.getSimpleName();
    public static final String ACTION = "broadcast.ExplicitAndImplicitReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive start");

        if (intent == null) {
            Log.i(TAG, "intent is null");
            return;
        }
        String action = intent.getAction();
        if (action == null) {
            Log.i(TAG, "action is null");
            return;
        }
        if (!action.equals(ACTION)) {
            Log.i(TAG, "action is not " + ACTION);
            return;
        }

        Log.i(TAG, "onReceive finish");
    }
}
2、Activity
  • activity_explicit_and_implicit_receiver_test.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ExplicitAndImplicitReceiverTestActivity">

    <Button
        android:id="@+id/btn_send_explicit_broadcast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送显式广播"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_send_implicit_broadcast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送隐式广播"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_send_explicit_broadcast" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • ExplicitAndImplicitReceiverTestActivity.java
java 复制代码
public class ExplicitAndImplicitReceiverTestActivity extends AppCompatActivity {

    public static final String TAG = ExplicitAndImplicitReceiverTestActivity.class.getSimpleName();

    private ExplicitAndImplicitReceiver explicitAndImplicitReceiver;

    private Button btnSendExplicitBroadcast;
    private Button btnSendImplicitBroadcast;

    @Override
    protected void onStart() {
        super.onStart();

        explicitAndImplicitReceiver = new ExplicitAndImplicitReceiver();

        IntentFilter intentFilter = new IntentFilter(ExplicitAndImplicitReceiver.ACTION);

        registerReceiver(explicitAndImplicitReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (explicitAndImplicitReceiver != null) unregisterReceiver(explicitAndImplicitReceiver);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_explicit_and_implicit_receiver_test);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        btnSendExplicitBroadcast = findViewById(R.id.btn_send_explicit_broadcast);
        btnSendImplicitBroadcast = findViewById(R.id.btn_send_implicit_broadcast);

        btnSendExplicitBroadcast.setOnClickListener(v -> {
            Log.i(TAG, "发送显式广播");
            Intent intent = new Intent(this, ExplicitAndImplicitReceiver.class);
            sendBroadcast(intent);
        });

        btnSendImplicitBroadcast.setOnClickListener(v -> {
            Log.i(TAG, "发送隐式广播");
            Intent intent = new Intent(ExplicitAndImplicitReceiver.ACTION);
            sendBroadcast(intent);
        });
    }
}
3、Test
(1)不指定 IntentFilter
java 复制代码
IntentFilter intentFilter = new IntentFilter();
  1. 发送显式广播,输出结果

    发送显式广播

  2. 发送隐式广播,输出结果

    发送隐式广播

(2)指定 IntentFilter
java 复制代码
IntentFilter intentFilter = new IntentFilter(ExplicitAndImplicitReceiver.ACTION);
  1. 发送显式广播,输出结果

    发送显式广播

  2. 发送隐式广播,输出结果

    发送隐式广播
    onReceive start
    onReceive finish

小结
  1. 动态注册的 Receiver 使用隐式广播

  2. 指定 IntentFilter

  3. Receiver 内可以不检查 action,直接接收广播(一个 action 的情况)

相关推荐
她的男孩3 分钟前
同一个接口,为什么销售只看到自己的订单?我拆了 681 行数据权限拦截器的源码
java·后端·架构
卓怡学长10 分钟前
w157基于springboot北部湾地区助农平台
java·spring boot·spring·maven·intellij-idea
小白羊丨11 分钟前
问数 Agent 整体架构、意图识别、历史上下文与 NL2SQL
java·面试·架构
Linux-lucky20 分钟前
33-Linux学习之旅之MySQL用户管理
java·linux·运维·学习·mysql·ubuntu
SimonKing25 分钟前
将cURL 命令直接变成 Java 代码?用JQuick-Curl搞起来
java·后端·程序员
大牧师29 分钟前
Nest.js 微服务入门教程
开发语言·javascript·后端·微服务·node.js·nest.js·nest
格林威32 分钟前
C# 图像异步落盘存储:基于Channel 配合 ArrayPool 实现异步落盘
开发语言·人工智能·数码相机·机器学习·计算机视觉·c#·视觉检测
软件黑马王子33 分钟前
11.缓存池优化:窗口布局
开发语言·前端框架·c#
凤山老林34 分钟前
企业级文件服务中台:Spring Boot 集成 MinIO 实现分片存储、生命周期管理与多租户隔离
java·spring boot·后端·minio·文件服务
青山木34 分钟前
Hot 100 --- 买卖股票的最佳时机
java·数据结构·算法·leetcode·贪心算法