Android 四大组件之BroadcastReceiver

本文详细介绍了Android中的BroadcastReceiver,包括广播接收者的使用、动态注册、发送有序和无序广播,以及Android 8.0以上版本的隐式广播规则变化。还列举了常用系统广播如电话、应用安装卸载、开机、短信、SD卡状态和屏幕解锁的处理。重点讨论了在API 26+中如何处理静态广播的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 四大组件之BroadcastReceiver


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.youkuaiyun.com/rozol/article/details/79606175


广播接收者
四大组件(Activity / BroadcastReceiver / Service / ContentProvider)之一
四大组件均运行于主线程

广播接收者

使用

  • 编写广播接受者代码

    public class AppStateReceiver extends BroadcastReceiver {
        private static final String TAG = AppStateReceiver.class.getSimpleName();
        @Override
        public void onReceive(Context context, Intent intent) {
            // 获取当前接收广播的动作
            String action = intent.getAction();
            // 获取应用Uri
            Uri packageUri = intent.getData(); // package:包名
            // 获取应用包名
            String packageName = intent.getDataString();
    
            if (action.equals("android.intent.action.PACKAGE_INSTALL") || action.equals("android.intent.action.PACKAGE_ADDED")){
                Log.i(TAG, "应用: " + intent.getDataString() + " 被安装了");
    
            } else if(action.equals("android.intent.action.PACKAGE_REMOVED")){
                Log.i(TAG, "应用: " + intent.getDataString() + " 被卸载了");
            }
        }
    }
    
  • 配置监听广播事件

    <receiver android:name=".AppStateReceiver">
        <intent-filter>
            <action android:name="android.intent.action.PACKAGE_INSTALL"/>
            <action android:name="android.intent.action.PACKAGE_ADDED"/>
            <action android:name="android.intent.action.PACKAGE_REMOVED"/>
            <data android:scheme="package"/>
        </intent-filter>
    </receiver>
    

动态注册广播接收者

在清单文件里配置无效的广播接收者, 必须使用代码注册

  • 动态注册广播接收者

    private ScreenReceiver screenReceiver;
    /**
     * 动态注册特殊的广播
     * @param view
     */
    public void onclick2(View view){
        screenReceiver = new ScreenReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.SCREEN_OFF");
        filter.addAction("android.intent.action.SCREEN_ON");
        // 动态注册广播接收者
        registerReceiver(screenReceiver, filter);
    }
    
    @Override
    protected void onDestroy() {
        // 动态注销广播接收者
        unregisterReceiver(screenReceiver);
        super.onDestroy();
    }
    
  • ScreenReceiver 代码处理 (略)

发送广播

有序广播

  • 发送广播

    /**
     * 发送无序广播
     */
    public void onclick(View view){
        Intent intent = new Intent();
        intent.setAction("luzhuo.me");
        intent.putExtra("content", "这是一条无序广播.");
    
        // 发送一条无序广播
        // 只发送广播, 不管有没有接收, 且不可被 篡改 / 终止
        sendBroadcast(intent);
    }
    
  • 接收广播

    • 清单文件配置

      <receiver android:name=".my.MyBroadcastReceiver">
          <intent-filter>
              <action android:name="luzhuo.me"/>
          </intent-filter>
      </receiver>
      
    • 代码处理

      @Override
      public void onReceive(Context context, Intent intent) {
          String content = intent.getStringExtra("content");
          Log.i(TAG, content);
      }
      

无序广播

  • 发送广播

    /**
     * 发送有序广播
     */
    public void onclick1(View view){
        Intent intent = new Intent();
        intent.setAction("luzhuo.me.my");
    
        // 发送一条有序广播
        // 发送有序广播, 优先级最高(1000)最先被接收, 指定最终接收者(若指定不管是否被终止, 都可接收), 可被 篡改 / 终止
        // 最终广播接收者(MyOrderedBroadcast3)可不在清单文件中配置
        sendOrderedBroadcast(intent, null, new MyOrderedBroadcast3(), null, 1, "这是一条有序广播", null);
    }
    
  • 接收广播

    • 清单文件配置

      <receiver android:name=".my.MyOrderedBroadcast1">
          <intent-filter android:priority="1000">
              <action android:name="luzhuo.me.my"/>
          </intent-filter>
      </receiver>
      <receiver android:name=".my.MyOrderedBroadcast2">
          <intent-filter android:priority="100">
              <action android:name="luzhuo.me.my"/>
          </intent-filter>
      </receiver>
      
    • 代码处理

      // MyOrderedBroadcast1.class
      @Override
      public void onReceive(Context context, Intent intent) {
          // 获取广播发送的数据
          String content = getResultData();
          Log.i(TAG, content);
          // 篡改广播数据
          setResultData("数据已被篡改.");
      }
      
      // MyOrderedBroadcast2.class
      @Override
      public void onReceive(Context context, Intent intent) {
          String content = getResultData();
          Log.i(TAG, content);
          // 终止广播
          abortBroadcast();
      }
      
      // MyOrderedBroadcast3.class
      @Override
      public void onReceive(Context context, Intent intent) {
          String content = getResultData();
          Log.i(TAG, content);
      }
      

常用的系统广播

电话的呼入与呼出
  • 权限:

    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    
  • 配置:

    <receiver android:name=".CallReceiver">
        <intent-filter android:priority="1000">
            <!-- 接收的动作 -->
            <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
            <action android:name="android.intent.action.PHONE_STATE"/>
        </intent-filter>
    </receiver>
    
  • 接收处理代码

    @Override
    public void onReceive(Context context, Intent intent) {
        // <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    
        String action = intent.getAction();
        if (action.equals("android.intent.action.NEW_OUTGOING_CALL")) {
            // 获取号码
            String number = getResultData();
            setResultData("123456"); // 设置号码
    
            Log.i(TAG, "电话号码: " + number);
    
        //  <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
        } else if (action.equals("android.intent.action.PHONE_STATE")){
            TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
            int state = telephony.getCallState();
            switch (state) {
                case TelephonyManager.CALL_STATE_RINGING:
                    String phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                    Log.i(TAG, "电话号码: " + phoneNumber);
                    //等待
                    Log.i(TAG, "电话等待接通中");
                    break;
                case TelephonyManager.CALL_STATE_IDLE:
                    // 挂断
                    Log.i(TAG, "电话已被挂断");
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    // 接通
                    Log.i(TAG, "电话通话中");
                    break;
            }
        }
    }
    
应用的安装与卸载状态
  • 见 使用
开机
  • 权限:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    
  • 清单配置

    <receiver android:name=".BootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
        </intent-filter>
    </receiver>
    
  • 处理代码(略)

接收短信
  • 权限:

    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    
  • 清单配置

    <receiver android:name=".SMSReceiver">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
        </intent-filter>
    </receiver>
    
  • 处理代码

    public void onReceive(Context context, Intent intent) {
        // <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    
        // 获取短信号码和内容
        Object[] objects = (Object[]) intent.getExtras().get("pdus");
        for (Object pdu : objects){
            SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
    
            // 发送短信的内容
            String body = smsMessage.getMessageBody();
            // 发送者
            String address = smsMessage.getOriginatingAddress();
    
            Log.i(TAG, "发送者: " + address);
            Log.i(TAG, "短信内容: " + body);
        }
    }
    
SD卡挂在与弹出
  • 权限:

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    
  • 清单配置

    <receiver android:name=".SDCardReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
            <action android:name="android.intent.action.MEDIA_MOUNTED"/>
            <data android:scheme="file"/>
        </intent-filter>
    </receiver>
    
  • 代码处理 (略)

屏幕的锁屏与解锁
  • 见 (广播接收者 - 动态注册广播接收者)

Android8.0 API26+ 隐式广播规则改变

  • Android8.0 API26+ 规则的改变, 使得大量在清单文件里配置的静态广播不再成功接收广播事件, 相应的在Log里会打印以下内容(Background execution not allowed: receiving Intent).

    2019-05-28 16:47:08.656 1118-1135/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.melon.lazymelon flg=0x4000010 (has extras) } to me.luzhuo.apprecorder/.receiver.NewAppReceiver
    2019-05-28 16:48:05.714 1118-1859/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.melon.lazymelon flg=0x4000010 (has extras) } to me.luzhuo.apprecorder/.receiver.NewAppReceiver
    
  • 也有部分的静态广播是可以被使用的, 见"不受限的系统广播"

受限的系统广播

  • 使用动态注册的方式接收广播
    • 清单文件依旧如此配置 (api26-还是可以用的)

      <receiver android:name=".receiver.AppStateReceiver" >
          <intent-filter>
              <action android:name="android.intent.action.PACKAGE_INSTALL"/>
              <action android:name="android.intent.action.PACKAGE_ADDED" />
              <action android:name="android.intent.action.PACKAGE_REMOVED" />
              <data android:scheme="package" />
          </intent-filter>
      </receiver>
      
    • 再使用动态注册进行注册一遍

      /**
       * 动态注册广播, 解决 api26+ 隐式广播限制
       */
      private void registerBroadcast() {
          appStateReceiver = new AppStateReceiver();
          IntentFilter filter = new IntentFilter();
          filter.addAction("android.intent.action.PACKAGE_INSTALL");
          filter.addAction("android.intent.action.PACKAGE_ADDED");
          filter.addAction("android.intent.action.PACKAGE_REMOVED");
          filter.addDataScheme("package");
          registerReceiver(appStateReceiver, filter);
      }
      
      @Override
      protected void onDestroy() {
          unregisterReceiver(appStateReceiver);
          super.onDestroy();
      }
      

不受限的系统广播

  • 系统还有一些不受限制的, 依旧可以使用静态注册方式

  • 静态注册

    <receiver android:name=".receiver.LanguageReceiver">
        <intent-filter>
            <action android:name="android.intent.action.LOCALE_CHANGED"/>
        </intent-filter>
    </receiver>
    
  • 其他不受限系统广播的清单

Implicit Broadcast ExceptionsDescription
ACTION_LOCKED_BOOT_COMPLETED / ACTION_BOOT_COMPLETED只在首次启动时发送一次, 以便进行作业、闹铃等事项的安排
ACTION_USER_INITIALIZE / "android.intent.action.USER_ADDED" / "android.intent.action.USER_REMOVED"受特权保护, 大多数正常应用无法接收它们
"android.intent.action.TIME_SET" / ACTION_TIMEZONE_CHANGED / ACTION_NEXT_ALARM_CLOCK_CHANGED时钟应用可能需要接收这些广播, 以便更新闹铃
ACTION_LOCALE_CHANGED只在语言区域发生变化时发送
ACTION_USB_ACCESSORY_ATTACHED / ACTION_USB_ACCESSORY_DETACHED / ACTION_USB_DEVICE_ATTACHED / ACTION_USB_DEVICE_DETACHEDUSB相关事件
ACTION_CONNECTION_STATE_CHANGED / ACTION_CONNECTION_STATE_CHANGED / ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED蓝牙事件
ACTION_CARRIER_CONFIG_CHANGED / TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED / "TelephonyIntents.SECRET_CODE_ACTION" / ACTION_PHONE_STATE_CHANGED / ACTION_PHONE_ACCOUNT_REGISTERED / ACTION_PHONE_ACCOUNT_UNREGISTEREDOEM电话应用需要的广播
LOGIN_ACCOUNTS_CHANGED_ACTION登录帐号的变化
ACTION_ACCOUNT_REMOVED删除账户
ACTION_PACKAGE_DATA_CLEARED用户从 Settings 清除数据时发送
ACTION_PACKAGE_FULLY_REMOVED软件包被移除时
ACTION_NEW_OUTGOING_CALL用户拨打电话行为
ACTION_DEVICE_OWNER_CHANGED设备的安全状态已经改变
ACTION_EVENT_REMINDER由"日历提供商"发送, 以向日历应用发布活动提醒
ACTION_MEDIA_MOUNTED / ACTION_MEDIA_CHECKING / ACTION_MEDIA_UNMOUNTED / ACTION_MEDIA_EJECT / ACTION_MEDIA_UNMOUNTABLE / ACTION_MEDIA_REMOVED / ACTION_MEDIA_BAD_REMOVAL用户与设备的物理交互 (安装或移除存储卷) 或启动初始化 (作为已装载的可用卷) 的一部分
SMS_RECEIVED_ACTION / WAP_PUSH_RECEIVED_ACTIONSMS收件应用需要的广播

受限制的自定义广播

  • 不指定接收者, 即隐式广播
    • 清单文件配置:

      <receiver android:name=".receiver.MyBroadcastReceiver">
          <intent-filter>
              <action android:name="luzhuo.me"/>
          </intent-filter>
      </receiver>
      
    • 发送隐式广播

      /**
       * 受限的自定义广播
       * @param view
       */
      public void myBroadcast(View view) {
          // 发送一条受限的自定义广播 (没有指定接收者, 即隐式广播)
          Intent intent = new Intent();
          intent.setAction("luzhuo.me");
          intent.putExtra("content", "这是一条无序广播.");
          sendBroadcast(intent);
      }
      

不受限制的自定义广播

  • 指定接收者和发送者, 即显示广播
    • 清单文件配置 (同 受限制的自定义广播)

    • 发送显示广播

      /**
       * 不受限的自定义广播
       * @param view
       */
      public void myBroadcastException(View view) {
          // 发送一条不受限的自定义广播 (指定接收者, 即显式广播)
          Intent intent = new Intent("me.luzhuo.broadcastreceiversdk26");
          intent.setPackage(getPackageName());
          intent.setAction("luzhuo.me");
          intent.putExtra("content", "这是一条无序广播.");
          sendBroadcast(intent);
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值