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

相关推荐
CoderYanger3 小时前
Java EE 进阶:8.MyBatis 操作数据库(入门)(第二弹)
java·数据库·spring boot·spring·面试·java-ee·mybatis
CQU_JIAKE5 小时前
11.7[高体】
java·后端·spring
apcipot_rain6 小时前
C++转Java日记(04)
java·开发语言·c++
特立独行的猫A7 小时前
我给女儿写了个打字练习:一边敲键盘,一边把小学英语单词记牢
java·后端·python
云和数据.ChenGuang8 小时前
LangGraph 异步 Node 的设计与写法实践
开发语言·人工智能·python·机器学习·php
金銀銅鐵8 小时前
同一个 Hello World,Kotlin 和 Java 在字节码层面差在哪
jvm·后端·kotlin
憧憬成为java架构高手的小白8 小时前
LangGraph4j 实战(下)
java
天诰9 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
蜗牛一步步往上爬11 小时前
第十六章 C++语言在深度学习中的应用
开发语言·c++·深度学习
好的佩奇12 小时前
Dart 之扩展方法
android·flutter·dart