Android广播知识详细解释

本文详细介绍了Android广播的基本原理、注册方式(静态与动态)及其区别,以及广播的五种分类:普通广播、系统广播、有序广播、黏性广播和本地广播。通过实例分析了各种广播的使用场景和注意事项,对于理解Android广播机制和优化应用中的广播使用具有指导意义。

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

广播是Android四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),在开发中应用广泛,下面是开发过程中对广播相关知识的总结。

1、广播的原理
2、广播的注册
3、广播的分类

1、广播的原理

广播接收器有两个端,一个是发送端,一个是接受端,整个框架是订阅模式。当调用接口发送广播消息后,AMS会将该消息转发给所有i监听该消息的接受端。(注:ActivityManagerService管理所有的四大组件,可深入看一下源码。)

广播接收器原理图

广播接收器原理图

2、广播的注册

根据广播接受器的原理,首先看一下广播接收器的注册过程。广播的注册有两种方式:

1.静态注册
2.动态注册

2.1 静态注册

·注册方式:在AndroidManifest.xml中通过标签注册。
·静态注册个属性详解

<receiver
            android:enabled="true" | "false"
            // 此BroadcastReceiver能否接收其他APP发出的广播
            // 如果是true,则是个本地广播接收器,只能接收本APP进程内的广播
            // 默认值是由Receiver中有误intent-filter决定的,如果有intent-filter,默认值是true,否则是false
            android:exported="true" | "false"
            android:icon="R.drawable.ic_boradcast"
            android:label="R.string.label_broadcast"
            // 需要在src下新建文件TestBroadcastReceiver,并继承自BoradcastReceiver
            android:name=".TestBroadcastReceiver"
            // 具有相应权限的广播发送者发送的广播,才能被此BroadcastReceiver所接收
            android:permission="string"
            // 指定BroadcastReceiver运行所处的进程
            // 默认是APP的进程,也可以指定独立的进程
            android:process="string" >
            <intent-filter>
                <action android:name="com.broadcast.change"/>
            </intent-filter>
        </receiver>

·代码示例

<receiver 
    android:name=".TestBroadReceiver" >  
        <intent-filter >  
            <action android:name="com.broadcast.change" />
        </intent-filter>  
</receiver>

同时,Java文件还需要实现该广播接收器。

public class TestBroadReceiver extends BroadcastReceiver {
    private static final String TAG = "TakePhotoReceiver";    

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("com.broadcast.change".equals(action)) {
            // do something..
        }
    }
 }

当APP首次启动后,会主动实例化TestBroadcastReceiver,并注册到系统中。

2.2 动态注册


public class MainActivity extends AppCompatActivity {
    private final static String TAG = "MainActivity";

    // @Step1 实例化一个广播接收器,并重写onReceiver()方法,当需要的广播到达时,会回调此方法。
    // 此广播实现的是,当网络发生变化时,销毁当前activity
    private final BroadcastReceiver mBatChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if ("com.broadcast.change".equals(action)) {
                finish();
            }
        }
    };

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

    @Override
    protected void onResume() {
        super.onResume();
        // @Step2 设置需要监听的广播类型
        IntentFilter intentFilter = new IntentFilter("com.broadcast.change");
        // @Step3 向系统注册该广播, Context.registerReceiver();
        registerReceiver(mBatChangeReceiver, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // @Step4 广播接收器使用完毕后,需要销毁
        if (mBatChangeReceiver != null) {
            try {
                unregisterReceiver(mBatChangeReceiver);
            } catch (Exception e) {
                Log.e(TAG, "unregisterReceiver fail: " + e.getCause());
            }
        }
    }
}

对于动态广播,注册和销毁是成对存在的,所有建议在onResume()、onPause进程注册和销毁。 广播是不允许重复注册、重复销毁的,两者都会报错。 如果在退出的时候没有销毁广播,会造成内存泄露

2.3 静态注册和动态注册的区别

静态注册和动态注册区别

注:
对于系统广播,系统内部直接发出的,从3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。具体介绍可以参考:https://blog.youkuaiyun.com/ocean2006/article/details/40806819

3.广播的分类

·普通广播(Normal Broadcast)
·系统广播(System Broadcast)
·有序广播(Ordered Broadcast)
·黏性广播(Sticky Broadcast)
·本地广播(Local Broadcast)

3.1普通广播

普通广播是应用开发者使用最多的广播,具体使用方式如下:

Intent intent = new Intent();
intent.setAction("com.broadcast.change");
intent.putExtra("data", "idle");
sendBroadcast(intent);

这里发送广播后,如果应用监听了该广播,就会回调该广播接收器的onReceive()方法。

3.2系统广播

Android有很多原生的广播,属于系统级的,如开机广播、网络变化等等,系统都会发出相应的广播,APP可以监听这些系统广播。系统广播的发送者就是系统,我们只需要实现接收器就可以。

Intent.ACTION_AIRPLANE_MODE_CHANGED关闭或打开飞行模式时的广播
Intent.ACTION_BATTERY_CHANGED充电状态,或者电池的电量发生变化;电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册
Intent.ACTION_BATTERY_LOW表示电池电量低
Intent.ACTION_BATTERY_OKAY表示电池电量充足,即从电池电量低变化到饱满时会发出广播
Intent.ACTION_BOOT_COMPLETED在系统启动完成后,这个动作被广播一次(只有一次)
Intent.ACTION_CAMERA_BUTTON按下照相时的拍照按键(硬件按键)时发出的广播
Intent.ACTION_CLOSE_SYSTEM_DIALOGS当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息
Intent.ACTION_CONFIGURATION_CHANGED设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java)
Intent.ACTION_DATE_CHANGED设备日期发生改变时会发出此广播
Intent.ACTION_DEVICE_STORAGE_LOW设备内存不足时发出的广播,此广播只能由系统使用,其它APP不可用
Intent.ACTION_DEVICE_STORAGE_OK设备内存从不足到充足时发出的广播,此广播只能由系统使用,其它APP不可用
Intent.ACTION_DOCK_EVENT发出此广播的地方frameworks\base\services\java\com\android\server\DockObserver.java
Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE移动APP完成之后,发出的广播(移动是指:APP2SD)
Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE正在移动APP时,发出的广播(移动是指:APP2SD)
Intent.ACTION_GTALK_SERVICE_CONNECTEDGtalk已建立连接时发出的广播
Intent.ACTION_GTALK_SERVICE_DISCONNECTEDGtalk已断开连接时发出的广播
Intent.ACTION_HEADSET_PLUG在耳机口上插入耳机时发出的广播
Intent.ACTION_INPUT_METHOD_CHANGED改变输入法时发出的广播
Intent.ACTION_LOCALE_CHANGED设备当前区域设置已更改时发出的广播
Intent.ACTION_MANAGE_PACKAGE_STORAGE
Intent.ACTION_MEDIA_BAD_REMOVAL未正确移除SD卡(正确移除SD卡的方法:设置–SD卡和设备内存–卸载SD卡),但已把SD卡取出来时发出的广播; 广播:扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount)
Intent.ACTION_MEDIA_BUTTON按下”Media Button” 按键时发出的广播,假如有”Media Button” 按键的话(硬件按键)
Intent.ACTION_MEDIA_CHECKING插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播?
Intent.ACTION_MEDIA_EJECT已拔掉外部大容量储存设备发出的广播(比如SD卡,或移动硬盘),不管有没有正确卸载都会发出此广播?; 广播:用户想要移除扩展介质(拔掉扩展卡)。
Intent.ACTION_MEDIA_MOUNTED插入SD卡并且已正确安装(识别)时发出的广播;广播:扩展介质被插入,而且已经被挂载
Intent.ACTION_MEDIA_NOFS
Intent.ACTION_MEDIA_REMOVED外部储存设备已被移除,不管有没正确卸载,都会发出此广播?;广播:扩展介质被移除。
Intent.ACTION_MEDIA_SCANNER_FINISHED广播:已经扫描完介质的一个目录
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
Intent.ACTION_MEDIA_SCANNER_STARTED广播:开始扫描介质的一个目录
Intent.ACTION_MEDIA_UNMOUNTABLE
Intent.ACTION_MEDIA_UNMOUNTED广播:扩展介质存在,但是还没有被挂载 (mount)。
Intent.ACTION_NEW_OUTGOING_CALL
Intent.ACTION_PACKAGE_ADDED设备上新安装了一个应用程序包。一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_CHANGED一个已存在的应用程序包已经改变,包括包名
Intent.ACTION_PACKAGE_DATA_CLEARED清除一个应用程序的数据时发出的广播(在设置--应用管理--选中某个应用,之后点清除数据时?)用户已经清除一个包的数据,包括包名(清除包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_INSTALL触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用
Intent.ACTION_PACKAGE_REMOVED成功的删除某个APK之后发出的广播;一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_REPLACED替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播?)
Intent.ACTION_PACKAGE_RESTARTED用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)
Intent.ACTION_POWER_CONNECTED插上外部电源时发出的广播
Intent.ACTION_POWER_DISCONNECTED已断开外部电源连接时发出的广播
Intent.ACTION_PROVIDER_CHANGED
Intent.ACTION_REBOOT重启设备时的广播
Intent.ACTION_SCREEN_OFF屏幕被关闭之后的广播
Intent.ACTION_SCREEN_ON屏幕被打开之后的广播
Intent.ACTION_SHUTDOWN关闭系统时发出的广播
Intent.ACTION_TIMEZONE_CHANGED时区发生改变时发出的广播
Intent.ACTION_TIME_CHANGED时间被设置时发出的广播
Intent.ACTION_TIME_TICK广播:当前时间已经变化(正常的时间流逝)。当前时间改变,每分钟都发送,不能通过组件声明来接收,只有通过Context.registerReceiver()方法来注册
Intent.ACTION_UID_REMOVED一个用户ID已经从系统中移除发出的广播
Intent.ACTION_UMS_CONNECTED设备已进入USB大容量储存状态时发出的广播
Intent.ACTION_UMS_DISCONNECTED设备已从USB大容量储存状态转为正常状态时发出的广播
Intent.ACTION_USER_PRESENT
Intent.ACTION_WALLPAPER_CHANGED设备墙纸已改变时发出的广播

3.3有序广播(Ordered Broadcast)

对于有序广播,广播接收者的接收是有顺序的,优先级高的先收到。
使用方式:

sendOrderedBroadcast();

接收器优先级原则:
按照priority的值,从大到小,优先级从高到低。
priority相同的,动态注册的优先。

注:android:priority=”100”,这个属性是用在标签里面的,如

<receiver android:name="AlarmInitReceiver" >            
    <intent-filter android:priority="100">
        <action android:name="android.intent.action.ACTION_BOOT_IPO" />
    </intent-filter>
</receiver>

这个属性只对两个组件起作用,就是Activity和Receiver,有的博客说在Service中添加这个属性可以保活,经验证,没有效果。Service保活可用以下方式:

1.不被杀死的service如何实现(设置成前台进程是惟一途径)
1. startService() 启动
2.startForegroud() 设置为前台程序

2. 如果要求进程必须是后台的怎么办 (可重启的service)
1. onStartCommand return START_STICKY
2. service 中 onDestory() 重启自己
3. 接收广播,重启自己。

对于Activity,使用priority属性,是在隐式启动activity时,如果有多个activity都匹配成功,那么优先级高的activity将会被触发。
对于Receiver,就是作用在有序广播的情景下。

回到有序广播中,接收器接收到该广播后,可以调用abortBroadcast(),停止该广播的继续传播。

3.4本地广播

应用场景:
应用内通信,保护本应用的广播,不被其他应用接收到。
使用方式:

注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
在广播发送和接收时,增设相应权限permission,用于权限验证;
发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
通过intent.setPackage(packageName)指定报名

或者使用LocalBroadcastManager

LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
                mConversationSelfIdChangeReceiver,
                new IntentFilter(UIIntents.CONVERSATION_SELF_ID_CHANGE_BROADCAST_ACTION));

private final BroadcastReceiver mConversationSelfIdChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            // do something
            }
        }
    };
// 退出时注销
LocalBroadcastManager.getInstance(getActivity())
                .unregisterReceiver(mConversationSelfIdChangeReceiver);

3.5黏性广播(Sticky Broadcast)

在Android5.0 & API 21中已经失效,后续不再使用。

对于不同注册方式的广播接收器回调OnReceive(Context context,Intent
intent)中的context返回值是不一样的:
对于静态注册(全局+应用内广播),回调onReceive(context,intent)中的context返回值是:ReceiverRestrictedContext;
对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值