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

相关推荐
不知名的老吴2 小时前
聊一聊年轻的编程语言Golang与Rust
开发语言·golang·rust
SimonKing2 小时前
frontend-dev vs ui-ux-pro-max:谁才是Vibe Coding前端开发的“最强辅助”?
java·后端·程序员
小谢小哥2 小时前
57-数据同步方案详解
java·后端·架构
小何code2 小时前
【Python零基础入门】第6篇:Python字符串入门:创建、索引与切片
开发语言·python
小谢小哥2 小时前
56-最终一致性方案详解
java·后端·架构
人道领域2 小时前
【Redis实战篇 | Day04】Lua原子性优化Redis分布式锁:解决线程安全问题
java·开发语言·redis·性能优化
恋奴娇2 小时前
ubuntu 25 Nautilus 文件管理器不能以ROOT运行突破
java·数据库·ubuntu
写了20年代码的老程序员2 小时前
微信支付回调里,为什么一行 data.order.amount 胜过五层判空
java