【Android】四大组件BroadcastReceiver

基础概念与作用

  • 基础概念
    • 用于接收系统或应用发出的广播消息(Intent),并在onReceive()方法中处理对应逻辑。
    • 是 Android 四大组件中唯一不依赖用户界面的组件,可异步响应事件。
  • 作用
    • 监听系统全局事件(如网络状态变化、电池电量低)或应用自定义事件(如数据更新通知)。

广播类型

1.标准广播

标准广播是一种无序广播,广播发出后,所有的接收者几乎同时接收到广播,接收者之间没有先后顺序。发送标准广播使用的是sendBroadcast()方法。例如,当设备的电池电量发生变化时,系统会发送一个标准广播,多个应用程序可以同时监听并处理这个广播,用于更新界面上的电量显示相关信息。

java 复制代码
public class MainActivity extends AppCompatActivity {

    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建广播接收器实例
        networkChangeReceiver = new NetworkChangeReceiver();

        // 创建IntentFilter并添加要监听的广播动作
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); // 网络状态变化广播

        // 动态注册广播接收器
        registerReceiver(networkChangeReceiver, intentFilter);

        // 发送自定义广播(示例)
        findViewById(R.id.send_broadcast_button).setOnClickListener(v -> {
            Intent customIntent = new Intent("com.example.CUSTOM_ACTION");
            customIntent.putExtra("message", "这是一条自定义广播");
            sendBroadcast(customIntent);
        });
    }


//    @Override
//    protected void onResume() {
//        super.onResume();
//        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
//        registerReceiver(receiver, filter);
//    }
//    @Override
//    protected void onPause() {
//        super.onPause();
//        unregisterReceiver(receiver);
//    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 注销广播接收器,防止内存泄漏
        unregisterReceiver(networkChangeReceiver);
    }

    // 自定义广播接收器类
    private class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
                // 处理网络变化事件
                ConnectivityManager cm = (ConnectivityManager)
                        context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
                boolean isConnected = activeNetwork != null &&
                        activeNetwork.isConnectedOrConnecting();

                String status = isConnected ? "网络已连接" : "网络已断开";
                Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
            }
            else if ("com.example.CUSTOM_ACTION".equals(action)) {
                // 处理自定义广播
                String message = intent.getStringExtra("message");
                Toast.makeText(context, "收到自定义广播: " + message, Toast.LENGTH_SHORT).show();
            }
        }
    }
}    

2.有序广播

广播发出后,系统会根据接收者的优先级依次接收广播。优先级可以在注册广播接收者时通过android:priority属性来设定。接收者可以消费广播(调用abortBroadcast()方法),这样后面的接收者就无法接收到该广播了。 例如,当设备收到一个短信的广播,安全软件可以优先接收这个广播,判断短信是否为垃圾短信,如果是,就消费该广播,避免后续的应用程序接收到垃圾短信的广播。

java 复制代码
private void sendOrderedBroadcast() {
    // 创建广播意图
    Intent intent = new Intent(ACTION_ORDERED_BROADCAST);

    // 设置初始数据
    Bundle bundle = new Bundle();
    bundle.putString("data", "初始数据");

    // 发送有序广播
    // 参数说明:
    // 1. 广播意图
    // 2. 接收权限(null表示不需要权限)
    // 3. 最终接收器(所有优先级接收器处理完后最后执行,可为null)
    // 4. 处理线程(null表示主线程)
    // 5. 初始结果码
    // 6. 初始结果数据
    // 7. 初始结果 extras
    sendOrderedBroadcast(intent, null, null, null,
            RESULT_OK, "初始结果数据", bundle);
}
java 复制代码
public class HighPriorityReceiver extends BroadcastReceiver {
    private static final String TAG = "HighPriorityReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("com.example.ORDERED_BROADCAST".equals(action)) {
            Log.d(TAG, "接收到有序广播");
            
            // 获取广播携带的数据
            Bundle bundle = getResultExtras(true);
            String originalData = bundle.getString("data", "默认数据");
            Log.d(TAG, "原始数据: " + originalData);
            
            // 修改广播数据
            bundle.putString("data", originalData + " -> 高优先级接收器修改后");
            setResultExtras(bundle);
            
            // 不拦截广播,继续传递给下一个接收器
            // 如果调用abortBroadcast(),则低优先级接收器无法收到广播
            // abortBroadcast();
        }
    }
}    
java 复制代码
public class LowPriorityReceiver extends BroadcastReceiver {
    private static final String TAG = "LowPriorityReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("com.example.ORDERED_BROADCAST".equals(action)) {
            Log.d(TAG, "接收到有序广播");
            
            // 获取高优先级接收器修改后的数据
            Bundle bundle = getResultExtras(true);
            String modifiedData = bundle.getString("data", "无数据");
            Log.d(TAG, "接收到的数据: " + modifiedData);
            
            // 低优先级接收器可以继续修改数据
            bundle.putString("data", modifiedData + " -> 低优先级接收器修改后");
            setResultExtras(bundle);
        }
    }
}   

注册方式

1.静态注册

  • AndroidManifest.xml中声明<receiver>标签,需指定intent-filter

  • 特点

    • 即使应用未启动,也能接收广播(如开机完成广播ACTION_BOOT_COMPLETED)。
    • 系统资源消耗较高,需谨慎使用(部分系统广播仅允许系统应用静态注册)
xml 复制代码
<receiver android:name=".MyReceiver"> 
    <intent-filter> 
    <action android:name="android.intent.action.NETWORK_STATE_CHANGED" /> 
    </intent-filter> 
</receiver>

2.动态注册

  • 通过Context.registerReceiver(receiver, filter)在代码中注册,需创建BroadcastReceiver实例和IntentFilter

  • 特点

    • 生命周期与注册组件(如 Activity)绑定,组件销毁时需调用unregisterReceiver()解注册,否则可能导致内存泄漏。
    • 适合监听仅在组件活跃时需要响应的广播(如 Activity 可见时监听屏幕旋转)。
java 复制代码
private NetworkChangeReceiver networkChangeReceiver;

@Override
protected void onResume() {
    super.onResume();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); // 网络状态变化广播
    registerReceiver(receiver, filter);
}
@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(receiver);
}

生命周期

1. 广播接收器的生命周期

1.创建阶段

  • 静态注册

    • 应用安装时由系统解析 AndroidManifest.xml 中的<receiver>标签创建,无需应用启动即可接收广播。

    • 示例:

      xml 复制代码
      <receiver android:name=".MyReceiver">
          <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED" />
          </intent-filter>
      </receiver>
  • 动态注册

    • 在代码中通过context.registerReceiver(receiver, filter)手动创建,需在组件(如 Activity)的生命周期内完成。

    • 示例:

      java 复制代码
      MyReceiver receiver = new MyReceiver();
      IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
      registerReceiver(receiver, filter); // 在Activity的onCreate()或onResume()中调用

2.接收广播阶段

  • 当系统或应用发送匹配的广播时,onReceive(Context context, Intent intent)方法被调用。

  • 关键限制

    • onReceive()必须在 10 秒内完成(前台广播)或几秒钟(后台广播),否则触发 ANR。
    • 禁止在onReceive()中执行耗时操作(如网络请求、数据库操作)。

3.销毁阶段

  • 静态注册

    • 随应用卸载自动销毁。
  • 动态注册

    • 需手动调用context.unregisterReceiver(receiver)注销,通常在组件销毁时(如 Activity 的onDestroy())执行。

    • 若未注销,可能导致内存泄漏或空指针异常(如 Activity 已销毁但接收器仍尝试操作 UI)。

2. 生命周期与组件的绑定关系

1.与Activity/Fragment绑定关系

广播接收器的生命周期依赖于绑定组件。

java 复制代码
public class MainActivity extends AppCompatActivity {
    private MyReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        receiver = new MyReceiver();
        registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver); // 必须注销
    }
}

2.与Service关系

若在 Service 中注册广播接收器,需在 Service 的onDestroy()中注销。

java 复制代码
public class MyService extends Service {
    private MyReceiver receiver;
    
    @Override
    public void onCreate() {
        super.onCreate();
        receiver = new MyReceiver();
        registerReceiver(receiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }
}

3. 最佳实践

  • 动态注册的位置选择
    • 若仅在 Activity 可见时接收广播,在onResume()中注册,onPause()中注销。
    • 若需在 Activity 整个生命周期接收,在onCreate()中注册,onDestroy()中注销。
  • 避免静态内部类持有外部类引用
    • 若使用内部类接收器,声明为static并通过弱引用访问外部类
java 复制代码
public class MainActivity extends AppCompatActivity {
    private static class MyReceiver extends BroadcastReceiver {
        private WeakReference<MainActivity> activityRef;

        public MyReceiver(MainActivity activity) {
            this.activityRef = new WeakReference<>(activity);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            MainActivity activity = activityRef.get();
            if (activity != null && !activity.isFinishing()) {
                // 安全操作Activity
            }
        }
    }
}
  • 使用 LocalBroadcastManager :
    • 若广播仅在应用内使用,推荐使用LocalBroadcastManager,避免跨应用安全风险,且无需担心权限问题。
java 复制代码
// 注册
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
// 发送
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
// 注销
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);

核心方法和应用场景

1.核心方法

  1. onReceive()

    • 功能:这是广播接收器的核心方法,当广播被接收到时,系统会调用这个方法。它会在主线程中执行,所以在该方法中不能进行耗时操作,否则可能会阻塞主线程,影响应用的响应速度。
    • 参数
      • Context context :提供了广播接收者运行的上下文环境。可以使用这个上下文来启动新的Activity、获取系统服务等操作。例如,你可以通过context.startActivity()来启动一个新的Activity,用于显示接收到广播后的界面。
      • Intent intent :包含了广播的消息内容。你可以通过intent.getAction()获取广播的类型(action),使用intent.getExtras()获取广播携带的其他数据。例如,对于系统发出的电量变化广播,你可能通过intent.getIntExtra()来获取当前电量。
  2. abortBroadcast()

    • 功能:用于中断广播的传递。在有序广播中,如果一个广播接收者调用了这个方法,那么后续优先级较低的广播接收者将无法接收到该广播。这个方法在标准广播中无效,因为标准广播是无序的,所有的广播接收者几乎会同时接收到广播。
    • 注意 :使用abortBroadcast()需要谨慎,只有在特定情况下(如安全软件阻止垃圾短信的通知广播)才应该使用它,因为这可能会影响其他应用的正常功能。
  3. setResult()

    • 功能:在有序广播中,可以使用这个方法来设置广播的结果。结果可以包括一个整数值、一个字符串和一个Intent对象。后续的广播接收者可以获取并修改这个结果。
    • 示例:比如在一个需要多个应用处理的广播场景中,第一个接收者处理完后,可以设置结果来指示处理的状态,后续接收者可以基于这个结果继续处理或者放弃处理。
  4. getResultData()getResultExtras()

    • 功能 :用于获取前面广播接收者通过setResult()设置的结果数据。getResultData()返回的是字符串形式的结果,getResultExtras()返回的是Intent对象中的额外数据。
    • 应用场景 :在有序广播的多个接收者之间进行数据传递和协作。例如,广播接收者A处理完数据后,通过setResult()设置结果,广播接收者B可以使用getResultData()getResultExtras()来获取这个结果,继续进行后续处理。

2.应用场景

  1. 开机启动应用

    • 原理 :系统在开机完成后会发送一个BOOT_COMPLETED广播。应用可以注册一个广播接收者来监听这个广播,当接收到广播后,启动应用的主Activity或者后台服务。

    • 代码示例(在AndroidManifest.xml中静态注册)

      xml 复制代码
      <receiver
          android:name=".BootReceiver"
          android:enabled="true"
          android:exported="true">
          <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED" />
          </intent-filter>
      </receiver>

      对应的广播接收者类:

      java 复制代码
      public class BootReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
                  // 启动应用主Activity
                  Intent i = new Intent(context, MainActivity.class);
                  i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                  context.startActivity(i);
              }
          }
      }
    • 注意 :为了能够接收开机广播,需要在应用的AndroidManifest.xml中添加RECEIVE_BOOT_COMPLETED权限。

  2. 监听系统广播(如电量变化、网络状态变化)

    • 电量变化监听

      • 原理 :系统会定期发送电量变化的广播(BATTERY_CHANGED)。通过注册广播接收者来监听这个广播,可以获取当前电量信息,用于显示电量状态或者在电量低时提醒用户。

      • 代码示例(动态注册)

        java 复制代码
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(batteryReceiver, filter);

        广播接收者类:

        java 复制代码
        private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
                int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
                float batteryPct = level / (float)scale;
                // 更新电量显示
                Log.d("BatteryLevel", "Battery level: " + batteryPct);
            }
        };
    • 网络状态变化监听

      • 原理 :系统会发送网络连接状态变化的广播,如CONNECTIVITY_ACTION。广播接收者可以监听这个广播来判断网络连接是否可用、网络类型(Wi - Fi、移动网络等)。

      • 代码示例(动态注册)

        java 复制代码
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(networkReceiver, filter);

        广播接收者类:

        java 复制代码
        private BroadcastReceiver networkReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
                if (activeNetwork != null && activeNetwork.isConnected()) {
                    String type = activeNetwork.getTypeName();
                    // 更新网络状态显示
                    Log.d("NetworkStatus", "Network connected, type: " + type);
                } else {
                    Log.d("NetworkStatus", "Network disconnected");
                }
            }
        };
  3. 应用内通信

    • 原理:应用内的不同组件之间可以通过广播来进行通信。例如,一个Activity可以发送一个广播,另一个Activity或者Service作为广播接收者来接收这个广播,从而实现组件之间的解耦。

    • 代码示例(发送广播)

      java 复制代码
      // 发送自定义广播
      Intent intent = new Intent("com.example.CUSTOM_ACTION");
      intent.putExtra("message", "Hello from Activity");
      sendBroadcast(intent);

      广播接收者类:

      java 复制代码
      public class CustomReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              String message = intent.getStringExtra("message");
              // 处理接收到的消息
              Log.d("CustomReceiver", "Received message: " + message);
          }
      }
    • 应用场景:在一个电商应用中,购物车页面的Activity可以发送一个广播,通知商品详情页面的Activity更新商品购买数量等信息。

  4. 定时任务提醒

    • 原理 :可以结合AlarmManager来发送定期广播。设置一个定时的广播,当到达指定时间时,广播接收者接收广播并执行相应操作,如提醒用户有预约的会议、发送定期推送消息等。

    • 代码示例(设置定时广播)

      java 复制代码
      Intent intent = new Intent(context, AlarmReceiver.class);
      PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
      AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
      long triggerTime = System.currentTimeMillis() + 10 * 60 * 1000; // 10分钟后
      alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);

      广播接收者类:

      java 复制代码
      public class AlarmReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              // 执行定时任务,如显示通知提醒
              NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
              Notification notification = new NotificationCompat.Builder(context, "reminder_channel")
                  .setContentTitle("Reminder")
                  .setContentText("Your scheduled reminder")
                  .setSmallIcon(R.drawable.ic_notification)
                  .build();
              notificationManager.notify(1, notification);
          }
      }
    • 注意:从Android 8.0(API级别26)开始,通知需要设置通知渠道,所以需要在代码中添加通知渠道的创建逻辑。

相关推荐
手机不死我是天子3 小时前
《Android 核心组件深度系列 · 第 2 篇 Service》
android
前行的小黑炭3 小时前
Compose页面切换的几种方式:Navigation、NavigationBar+HorizontalPager,会导致LaunchedEffect执行?
android·kotlin·app
前行的小黑炭4 小时前
Android :Comnpose各种副作用的使用
android·kotlin·app
BD_Marathon17 小时前
【MySQL】函数
android·数据库·mysql
西西学代码18 小时前
安卓开发---耳机的按键设置的UI实例
android·ui
maki0771 天前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
千里马学框架1 天前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio
fundroid1 天前
掌握 Compose 性能优化三步法
android·android jetpack
TeleostNaCl1 天前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
旷野说1 天前
Android Studio Narwhal 3 特性
android·ide·android studio