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 的情况)

相关推荐
caimouse33 分钟前
reactos编码规范
c语言·开发语言
xieliyu.5 小时前
Java算法精讲:双指针(三)
java·开发语言·算法
明夜之约5 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee5 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Jinkxs5 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
辣机小司5 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
数智工坊5 小时前
机器人运动控制:采样、优化与学习三大流派深度对比与实战
android·学习·机器人
CryptoPP6 小时前
快速对接东京证券交易所API数据:实战指南与代码示例
开发语言·人工智能·windows·python·信息可视化·区块链
ZC跨境爬虫6 小时前
跟着 MDN 学JavaScript day_7:数学运算与逻辑判断实战测试
开发语言·前端·javascript·学习·ecmascript
fangdengfu1236 小时前
ES分析系统各个服务日志占用量
java·前端·elasticsearch