测试引入
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
-
发送显式广播,输出结果
发送显式广播
-
发送隐式广播,输出结果
发送隐式广播
(2)声明 receiver,不声明 intent-filter
xml
<receiver
android:name=".mybroadcast.ExplicitAndImplicitReceiver"
android:exported="false" />
-
发送显式广播,输出结果
发送显式广播
onReceive start
action is null -
发送隐式广播,输出结果
发送隐式广播
(3)声明 receiver,声明 intent-filter(匹配的 action)
-
发送显式广播,输出结果
发送显式广播
onReceive start
action is null -
发送隐式广播,输出结果
理想情况
发送隐式广播
onReceive start
onReceive finish实际情况
发送隐式广播
(4)声明 receiver,声明 intent-filter(不匹配的 action)
-
发送显式广播,输出结果
发送显式广播
onReceive start
action is null -
发送隐式广播,输出结果
理想情况
发送隐式广播
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+ 被限制 |
-
静态注册的 Receiver 使用显式广播
-
可以不加 intent-filter(加不加都可以收到)
-
Receiver 内可以不检查 action,直接接收广播
-
如果要检查 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+ 对隐式广播的限制
-
从 Android 8.0(API 26)开始,静态注册的广播接收器无法接收大多数隐式广播
-
除非是豁免的广播,例如,系统广播
动态注册测试
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();
-
发送显式广播,输出结果
发送显式广播
-
发送隐式广播,输出结果
发送隐式广播
(2)指定 IntentFilter
java
IntentFilter intentFilter = new IntentFilter(ExplicitAndImplicitReceiver.ACTION);
-
发送显式广播,输出结果
发送显式广播
-
发送隐式广播,输出结果
发送隐式广播
onReceive start
onReceive finish
小结
-
动态注册的 Receiver 使用隐式广播
-
指定 IntentFilter
-
Receiver 内可以不检查 action,直接接收广播(一个 action 的情况)