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

相关推荐
考虑考虑5 小时前
JDK26中的Map.ofLazy
java·后端·java ee
鶴哥只手遮天8 小时前
Spring AI 2.0.1 深度解析-第 14 章 MCP 服务端(上):注解式实现与工具来源
java·人工智能·开源
鶴哥只手遮天8 小时前
Spring AI 2.0.1 深度解析-第 15 章 MCP 服务端(下):三种协议形态、Streamable 传输与状态管理
java·人工智能·开源
alexhilton8 小时前
Room Fts4:全文搜索替代 SQL LIKE
android·kotlin·android jetpack
鶴哥只手遮天8 小时前
Spring AI 2.0.1 深度解析-第 16 章 向量存储(上):`VectorStore` 接口体系、`BatchingStrategy`
java·人工智能·开源
鶴哥只手遮天8 小时前
Spring AI 2.0.1 深度解析-第 12 章 工具循环的流式形态、Usage 累加与扩展体系
java·人工智能·开源
鶴哥只手遮天8 小时前
Spring AI 2.0.1 深度解析-第 23 章 模型供应商实现:从 `OpenAiSetup` 到 Bedrock
java·人工智能·开源
鶴哥只手遮天8 小时前
Spring AI 2.0.1 深度解析-第 06 章 内置 Advisor 全景:13 个实现逐个剖到源码级
java·人工智能·开源
鶴哥只手遮天9 小时前
Spring AI 2.0.1 深度解析-第 03 章 消息体系与 Prompt:不可变模型、`ChatOptions` 与模板渲染
java·人工智能·开源
鶴哥只手遮天9 小时前
Spring AI 2.0.1 深度解析-第 24 章 生产实践与 2.x 迁移:陷阱清单、AOT 与调优
java·人工智能·开源