【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)开始,通知需要设置通知渠道,所以需要在代码中添加通知渠道的创建逻辑。

相关推荐
爬山算法2 小时前
MySQL(84)如何配置MySQL防火墙?
android·数据库·mysql
爬山算法2 小时前
MySQL(83)如何设置密码复杂度策略?
android·数据库·mysql
鹏说大数据2 小时前
MySQL5.7 慢查询SQL语句集合
android·sql·adb
锋风3 小时前
安卓官方版fat-aar:使用Fused Library将多个Android库发布为一个库
android
Renounce3 小时前
【Android】四大组件ContentProvider
android
雨白4 小时前
用 Kotlin 协程构建一个前台服务
android
东风西巷6 小时前
有道翻译官手机版:智能翻译,随行助手
android·智能手机·软件需求
_一条咸鱼_7 小时前
Android Gson基础数据类型转换逻辑(6)
android·面试·gson
_一条咸鱼_8 小时前
Android Runtime并发标记与三色标记法实现原理(55)
android·面试·android jetpack