Android 开发的四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),用于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。
一 相关感念
1.1 什么是广播
广播是Android中一种很重要的传递消息的方式。
BroadcastReceiver就是应用程序间的通信的一个手段, 系统自己在很多时候都会发送广播,比如电量低或者充足,刚启动完,插入耳机,输入法改变等,当发生这些事件的时候系统都会发送广播,这个叫系统广播,每个APP都会收到,如果你想让你的应用在接收到这个广播的时候做一些操作,比如:系统开机后,就发送自己APP的消息。 当然我们也可以自己发广播,比如:接到服务端推送信息,用户在别处登录,然后应该强制用户下线回到登陆界面,并提示在别处登录。
广播具有以下特性:
1.广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁
2.广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框
3.最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉
4.耗时的较长的工作最好放在服务中完成
1.2 两种广播类型
标准广播(Normal broadcasts) 是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接受到这条广播消息,因此它们之间没有任何先后顺序可言,这种广播的效率会比较高,但同时也意味着它是无法被拦截的。
有序广播(Ordered broadcasts) 则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接受器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
二 接收系统广播
Android 内置了很多系统级别的广播,我们可以在应用中通过监听这些广播来得到各种系统的状态信息。比如手机开机后会发送一条广播,电池的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条广播等等。如果想要接受这些广播,就需要使用广播接收器。
2.1 两种注册广播的方式
2.2 动态注册实例
权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
监测网络是否可用
private NetWorkChangeReceiver netWorkChangeReceiver;
private IntentFilter intentFilter;
private void init() {
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
netWorkChangeReceiver = new NetWorkChangeReceiver();
//注册广播
registerReceiver(netWorkChangeReceiver,intentFilter);
}
private class NetWorkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//系统服务类
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
//判断网络是否可用
if (activeNetworkInfo!=null && activeNetworkInfo.isAvailable()){
Toast.makeText(BroadCastsActivity.this,"网络可用",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(BroadCastsActivity.this,"网络不可用",Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//销毁广播
unregisterReceiver(netWorkChangeReceiver);
}
2.3 静态注册实例(接收开机广播)
自定义一个BroadcastReceiver,重写onReceive完成事务处理
public class BootCompleteReceiver extends BroadcastReceiver {
private final String ACTION_BOOT = "android.intent.action.BOOT_COMPLETED";
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_BOOT.equals(intent.getAction()))
Toast.makeText(context, "开机完毕~", Toast.LENGTH_LONG).show();
}
}
在AndroidManifest.xml中对该BroadcastReceiver进行注册,添加开机广播的intent-filter!
对了,别忘了加上android.permission.RECEIVE_BOOT_COMPLETED的权限哦!
<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<action android:name = "android.intent.cation.BOOT_COMPLETED">
</intent-filter>
</receiver>
<!-- 权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
三 发送广播
发送标准广播sendBroadcast()
发送有序广播sendOrderedBroadcast()
代码示例:(标准广播)
public class MyBroadcastReceiver extends BroadcastReceiver {
private final String ACTION_BOOT = "com.example.broadcasttest.MY_BROADCAST";
@Override
public void onReceive(Context context, Intent intent) {
if(ACTION_BOOT.equals(intent.getAction()))
Toast.makeText(context, "收到告白啦~",Toast.LENGTH_SHORT).show();
}
}
AndroidManifest.xml中注册,写上Intent-filter:
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
在MainActivity中完成广播发送:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_send = (Button) findViewById(R.id.btn_send);
btn_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendBroadcast(new Intent("com.example.broadcasttest.MY_BROADCAST"));
}
});
}
}
四 本地广播
前面我们发送和接受的广播全部属于系统全局广播,即发出的广播可以被其它任何应用程序接收到,并且我们也可以接受来自于其它任何应用程序的广播。
为了解决广播安全性问题,Android 引入了一套本地广播机制,使用这个机制发出的广播只能在应用程序内部进行传递,并且广播接受器也只能接受来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
初始化广播:
private LocalBroadcastManager localBroadcastManager;
private void init() {
//获取实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("om.function.luo.LOCAL_BROADCAST");
LocalReceiver localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
}
发送本地广播
Intent intent = new Intent("om.function.luo.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
重写广播接受方法
private class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "本地广播.....", Toast.LENGTH_LONG).show();
}
}
注意:
本地广播是无法通过静态注册的方式来接收的,其实这也完全可以理解,因为静态注册主要是为了让程序在未启动的情况下也能接受到广播,而发送本地广播时,我们的程序已经启动了,因此也完全不需要使用静态注册的功能。
本地广播的优势
可以明确知道正在发送的广播不会离开我们的程序,因此不必担心机密数据泄露。
其它的程序无法将广播发送到我们程序内部,因此不需要担心会有安全漏洞问题。
发送本地广播比发送系统全局广播更加高效。
本地广播常用的地方:
类似 QQ强制下线功能,出现一个弹窗,杀死所有 Activity,强制进入登录页面
五 常用的系统广播总结
Intent.action.AIRPLANE_MODE;
//关闭或打开飞行模式时的广播
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_HEADSET_PLUG;
//在耳机口上插入耳机时发出的广播
Intent.ACTION_INPUT_METHOD_CHANGED;
//改变输入法时发出的广播
Intent.ACTION_LOCALE_CHANGED;
//设备当前区域设置已更改时发出的广播
Intent.ACTION_MEDIA_BAD_REMOVAL;
//未正确移除SD卡(正确移除SD卡的方法:设置--SD卡和设备内存--卸载SD卡),但已把SD卡取出来时发出的广播
//广播:扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount)
Intent.ACTION_MEDIA_CHECKING;
//插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播
Intent.ACTION_MEDIA_SCANNER_STARTED;
//广播:开始扫描介质的一个目录
Intent.ACTION_PACKAGE_ADDED;
//成功的安装APK之后
//广播:设备上新安装了一个应用程序包。
//一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
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_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_WALLPAPER_CHANGED;
//设备墙纸已改变时发出的广播