1.需要一个过滤器
2.需要一个广播接收器
3.进行注册
4.取消注册
主要操作:使用registerReceiver
接受两个参数,一个是广播接收器BroadcastReceiver
,一个是意图IntentFiler
。现在注册完成,广播接收器就可以实现接受指定意图的广播.
最后需要记得对于动态注册的广播接收器一定要取消注册,我们在onDestroy()中通过调用unregisterReceiver
取消注册。传递的参数为:BroadcastReceiver
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
BroadcastReceiver NetwordChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
NetwordChangeReceiver = new NetwordChangeReceiver();
registerReceiver(NetwordChangeReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(NetwordChangeReceiver);
}
class NetwordChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
/** 制作一个网络管理器
* 它用于获取当前设备的网络连接状态信息。通过getSystemService方法,可以从系统服务中获取ConnectivityManager的实例。
*/
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
/**
* 使用网络工具类,从网络管理器中获取一个网络工具,这个工具有网络管理器的指定信息Context.CONNECTIVITY_SERVICE
*/
NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
if (networkCapabilities != null){
Toast.makeText(context, "netword is good", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "netWork is Poor", Toast.LENGTH_SHORT).show();
}
}
}
}
可以在下面这个路径查看系统广播列表:
Android/Sdk/platforms/<任意的android api 版本>/data/broadcast_actions.txt
注意静态广播需要在AndroidManifest.xml
中注册才可以使用,不过使用android stdio
的快捷方式可以实现自动注册。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.BroadcastReceiver"
tools:targetApi="31">
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
receiver>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
application>
manifest>
enabled、exported就是我们勾选的属性,不过此时的BootCompleteReceiver还是无法收到开机自启动广播,我们需要做如下操作:
添加,和应用权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
intent-filter>
public class MyBroadcateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcateRecevier", Toast.LENGTH_SHORT).show();
}
}
AndroidManifest.xml
中注册广播信息<receiver
android:name=".MyBroadcateReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.example.broadcastreceiver.MY_BROADCAST"/>
intent-filter>
receiver>
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
BroadcastReceiver NetwordChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.broadcastreceiver.MY_BROADCAST");
// intent.setPackage("com.example.broadcastreceiver");
intent.setPackage(getPackageName());
sendBroadcast(intent);
}
});
}
}
首先构建了一个Intent
对象,并把要发送的广播的值传入。然后调用Intent的setPackage()
方法,并传入当前应用程序的包名。getPackageName()
可以获取当前包名,用于获取当前应用程序的包名。最后调用sendBroadcast()
方法将广播发送出去,这样所有监听com.example.broadcastreceiver.MY_BROADCAST
这条广播的BroadcastReceiver
就会收 到消息了。此时发出去的广播就是一条标准广播
注意这个setPackage
的作用是指定这条广播发送给哪个程序,使得隐式广播转化为显式广播。因为Android8.0
以后,静态注册的BroadcastReceiver
是无法接受广播的。
在《第一行代码第二版》中,两个应用互相传递消息。在android 8.0之前是可以的,但是我们刚刚说android 8.0之后静态注册的BroadcastReceiver
是无法接受广播的。因此无法实现两个应用互相传递消息,解决方法很简单。指定第二个应用的包名,在传递一次即可。
public class AontherBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receciver in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();
Log.d("Broadcast","AnotherBroadcastReceiver");
}
}
在AndroidManifest.xml
中注册广播信息
<receiver
android:name=".MyBroadcateReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcastreceiver.MY_BROADCAST" />
intent-filter>
receiver>
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.broadcastreceiver.MY_BROADCAST");
intent.setPackage(getPackageName());
sendOrderedBroadcast(intent,null);
}
});
}
abortBroadcast
截断广播 <receiver
android:name=".MyBroadcateReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcastreceiver.MY_BROADCAST" />
intent-filter>
receiver>
android:priority="100"用于设置优先级为100
注意优先级大的先执行
,但是笔者的手机优先级大的会后执行优先级小的广播,具体什么问题笔者也不可知,笔者手机为一加Ace2,基于android 13.0。笔者怀疑这种情况可能是手机权限导致,其他经过测试android 13.0的手机优先级正常,大的优先级高先执行。
public class MyBroadcateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcateRecevier", Toast.LENGTH_SHORT).show();
Log.d("Broadcast","MyBroadcateRecevier");
abortBroadcast();
}
}
使用abortBroadcast()
可以截断广播,使得优先级在MyBroadcateReceiver
之后的BroadcateReceiver
无法接受到广播,广播在这里就被截断了。
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity){
activities.add(activity);
}
public static void delete(Activity activity){
activities.remove(activity);
}
public static void finishAll(){
for(Activity activity:activities){
if(!activity.isFinishing()){
activity.finish();
}
}
activities.clear();
}
}
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.delete(this);
}
}
用于注销所有的活动,实现一键退出功能。
<LinearLayout 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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_weight="1"
android:text="Account: "
android:gravity="center|end"/>
<EditText
android:id="@+id/account"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"/>
LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_weight="1"
android:text="Password: "
android:gravity="center|end"/>
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"/>
LinearLayout>
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_gravity="center"
android:text="Login"/>
LinearLayout>
public class LoginActivity extends BaseActivity {
ActivityLoginBinding binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityLoginBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String account = binding.account.getText().toString();
String password = binding.password.getText().toString();
if (account.equals("admin") && password.equals("123456")) {
Intent intent = new Intent(LoginActivity.this,MainActivity.class);
startActivity(intent);
}else {
Toast.makeText(LoginActivity.this, "password is poor", Toast.LENGTH_SHORT).show();
}
}
});
}
}
<LinearLayout 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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/force_offline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_gravity="center"
android:text="Send force offline Broadcast"/>
LinearLayout>
public class MainActivity extends BaseActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.force_offline);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.forcedoffine.FORCE_OFFLINE");
sendBroadcast(intent);
}
});
}
}
在BaseActivity中制作广播接收器
package com.example.forcedoffline;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
/**
* 项目名: ForcedOffline
* 文件名: BaseActivity
* 创建者: lukecc0
* 创建时间:2023/7/25 上午11:33
* 描述: TODO
*/
public class BaseActivity extends AppCompatActivity {
private ForceOfflineReceiver forceOfflineReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.delete(this);
}
@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.forcedoffine.FORCE_OFFLINE");
forceOfflineReceiver = new ForceOfflineReceiver();
registerReceiver(forceOfflineReceiver,intentFilter);
}
@Override
protected void onPause() {
super.onPause();
if(forceOfflineReceiver!=null){
unregisterReceiver(forceOfflineReceiver);
forceOfflineReceiver = null;
}
}
class ForceOfflineReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Warinng");
builder.setMessage("please try to login again");
builder.setCancelable(false);
builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCollector.finishAll();
Intent intent1 = new Intent(context, LoginActivity.class);
context.startActivity(intent1);
}
});
builder.show();
}
}
}
代码解释:
这样写的目的是为了确保在调用 unregisterReceiver()
注销广播接收器之后,再将 forceOfflineReceiver
设置为 null
,以避免在已经注销的广播接收器上继续操作而可能导致异常或其他问题。因为这里不是在onDestroy
中注销广播。
在 Android 应用的生命周期中,onResume()
和 onPause()
方法对应着 Activity 的可见性。当 Activity 处于可见状态时,会调用 onResume()
方法;当 Activity 处于不可见状态时,会调用 onPause()
方法。
如果我们将广播接收器的注册放在 onCreate()
中,那么广播接收器会在 Activity 创建时注册,但可能会出现以下问题:
onCreate()
中,但在 onPause()
或 onStop()
中没有注销,那么即使 Activity 不可见,广播接收器仍然保持注册状态,继续接收广播,这可能会导致资源浪费和不必要的逻辑执行。onDestroy()
中,那么在 Activity 被销毁时才会注销广播接收器。这样可能会导致在 Activity 不可见的时候仍然接收广播,直到 Activity 被销毁。这可能导致不必要的逻辑执行和资源浪费。