一、广播的定义
广播是一盒全局的监听器,属于 Android
四大组件之一。Android
广播分为两个角色:广播发送者、广播接收者。Android
的广播按照发送方式主要可以分成两种类型:标准广播和有序广播;按照注册方式主要可以分为:动态注册广播和静态注册广播;按照定义方式主要可以分为:系统广播和自定义广播。
1. 标准广播(Normal broadcasts)
一种完全异步执行的广播,广播发出去之后,所有的广播接收者几乎是同一时间收到消息的。他们之间没有先后顺序可言,而且这种广播是没法被截断的。
2. 有序广播
是一种同步执行的广播,在广播发出去之后,同一时刻只有一个广播接收器可以收到消息。当广播中的逻辑执行完成后,广播才会继续传播。
二、广播接收器(Broadcast Receivers)
广播接收器用于响应来自其他应用程序或者系统的广播消息。这些消息有时被称为事件或者意图。例如,应用程序可以初始化广播来让其他的应用程序知道一些数据已经被下载到设备,并可以为他们所用。这样广播接收器可以定义适当的动作来拦截这些通信。
有以下两个重要的步骤来使系统的广播意图配合广播接收器工作。
- 创建广播接收器
- 注册广播接收器
还有一个附加的步骤,要实现自定义的意图,你必须创建并广播这些意图。
1. 创建广播接收器
广播接收器需要实现为BroadcastReceiver
类的子类,并重写onReceive()
方法来接收以Intent
对象为参数的消息。
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
}
}
2. 注册广播接收器
应用程序通过在AndroidManifest.xml
中注册广播接收器来监听制定的广播意图。假设我们将要注册MyReceiver
来监听系统产生的ACTION_BOOT_COMPLETED
事件。该事件由Android系统的启动进程完成时发出。
根据注册方式又分为:动态注册、静态注册。
2.1 动态注册
简单来说就是通过代码添加响应的Action
。后面可以通过代码修改,不是固定的,所以称为动态注册。
在activity中通过代码动态注册广播,定义类extends BroadcastReceiver
,重写onReceiver
方法,通过registerReceiver
注册广播。在onDestory
方法中通过unregisterReceiver
取消注册。自由控制注册和取消,具有灵活性,缺点是程序启动后才能接受广播。
定义广播接收器:
class NetWorkReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
networkInfo = connectivityManager.getActiveNetworkInfo();//需要申请权限
if (networkInfo != null && networkInfo.isAvailable())
Toast.makeText(context,"网络开启了",Toast.LENGTH_SHORT).show();
else
Toast.makeText(context,"网络关闭了",Toast.LENGTH_SHORT).show();
}
}
在Activity
中创建实例:
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkInfo networkInfo;
private NetWorkReceiver netWorkReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
netWorkReceiver = new NetWorkReceiver();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//设置广播接收器接受的内容
registerReceiver(netWorkReceiver,intentFilter);//注册广播接收器
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注册广播接收器
unregisterReceiver(netWorkReceiver);
}
}
2.2 静态注册
在androidManifest.xml
文件中声明响应的Action
。
定义接收器:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"开机了!",Toast.LENGTH_LONG).show();
}
}
注册接收器:
<application>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
//广播接收器注册
<receiver android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action
android:name="android.intent.action.BOOT_COMPLETED"> </action>
</intent-filter>
</receiver>
</application>
有几个系统产生的事件定义在最后意图类的静态字段。下表列出了一些重要的系统事件。
事件常量 | 描述 |
---|---|
android.intent.action.BATTERY_CHANGED | 持久广播含充电状态,级别,以及其他相关的电池信息。 |
android.intent.action.BATTERY_LOW | 显示设备的电池电量低。 |
android.intent.action.BATTERY_OKAY | 指示电池正在低点后但没有问题。 |
android.intent.action.BOOT_COMPLETED | 一次播出后,系统已完成启动。 |
android.intent.action.BUG_REPORT | 显示活动报告的错误。 |
android.intent.action.CALL | 执行呼叫由数据指定某人。 |
android.intent.action.CALL_BUTTON | 用户按下“呼叫”按钮进入拨号器或其他适当的用户界面发出呼叫。 |
android.intent.action.DATE_CHANGED | 日期改变。 |
android.intent.action.REBOOT | 有设备重启。 |
3. 发送自定义广播并接收
1.发送标准广播
类继承BroadcastReceiver
,重写onReceiver
方法,在AndroidManifest
文件中声明:
public class MyBroadcastReceiver extends BroadcastReceiver {
@0verride
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceiver", Toast. LENGTH_SHORT).show();
}
}
注册:
<receiver
android: name=".MyBroadcastReceiver"
and roid: enabled="true"
android: exported="true">
<intent-filter>
<action android: name="com.example.broadcasttest.MY_BROADCAST"/>
</ intent-filter>
</ receiver>
发送广播:(可以是自己写的App)使用Intent发送自定义广播。
Intent intent = new Intent("com.override0330.example");
sendBroadcast(intent);
2.发送有序广播
步骤同发送标准广播一致,但是多加入一个优先级的设置。
......
<intent-filter android:priority="98">//设置优先级为98,最高为100
<action
android:name="com.override0330.example"></action>
</intent-filter>
......
发送有序广播:
Intent intent = new Intent("com.override0330.example");
sendOrderBroadcast(intent, null);//null参数为一个与权限相关的字符串,一般情况传入null
在广播接收器的onReceive
里使用abortBroadcast()
截断广播。
三、本地广播
优势:正在发送的广播不会离开我们的程序,不必担心数据泄露。其他程序无法将广播发送到我们程序内部,不必担心安全漏洞。发送本地广播比系统全局广播更高效。
private LocalReceiver localReceiver ;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState) ;
setContentView(R.layout.activity_main);
LocalBroadcastManager = LocalBroadcastManager.getInstance(this); //获取实例
Button button = (Button) findViewById(R.id.button) ;
button.setOnClickListener (new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcasttest.LOCAL_ BROADCAST");
localBroadcastManager.sendBroadcast(intent); // 发送本地广播
}
});
intentFilter = new IntentFilter();
intentFilter . addAction("com.example.broadcasttest.LOCAL_BROADCAST");
LocalReceiver = new LocaLReceiver();
//注册本地广播监听器
LocalBroadcastManager.registerReceiver(localReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注册
localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive (Context context, Intent intent) {
Toast.makeText (context, "received Local broadcast", Toast.LENGTH_ SHORT).show( ) ;
}
}
四、广播与服务
举个例子:模拟下载过程,下载时利用广播获取进度并实时更新进度条。
自定义下载服务:模拟下载过程并发送广播
public class MsgService extends Service {
/**
* 进度条的最大值
*/
public static final int MAX_PROGRESS = 100;
/**
* 进度条的进度值
*/
private int progress = 0;
private Intent intent = new Intent("com.example.communication.RECEIVER");
/**
* 模拟下载任务,每秒钟更新一次
*/
public void startDownLoad(){
new Thread(new Runnable() {
@Override
public void run() {
while(progress < MAX_PROGRESS){
progress += 5;
//发送Action为com.example.communication.RECEIVER的广播
intent.putExtra("progress", progress);
// ----------------发送广播--------------
sendBroadcast(intent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startDownLoad();
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
定义广播接收器:
public class MsgReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//拿到进度,更新UI
int progress = intent.getIntExtra("progress", 0);
mProgressBar.setProgress(progress);
}
}
注册广播接收器:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册广播接收器
msgReceiver = new MsgReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.communication.RECEIVER");
registerReceiver(msgReceiver, intentFilter);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
Button mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//启动服务
mIntent = new Intent("com.example.communication.MSG_ACTION");
startService(mIntent);
}
});
}
五、限制
Google为了降低功耗,改进Android系统的电池表现,为APP注册的静态广播导致耗电添加了限制。
Google所加入的限制很重要的一部分就是后台执行限制,其中对广播的限制为许多隐式广播无法在manifest中静态注册的BroadcastReceiver
收到(其实这一举措在Android7.0中已经初见端倪)。除了由系统发出的隐式广播之外,在应用中自定义的广播也无法被静态注册的BroadcastReceiver
收到。
那么问题来了,自定义的广播如何被静态注册的BroadcastReceiver
接收到呢?
解决方法有两种:
- 使用动态注册广播接收器,而不使用静态注册的广播接收器。
- 官方推荐使用
JobScheduler
替代原来用隐式广播实现功能,但是没有广播那么灵活。 - 发送广播之前,Intent调用
setPackage()
方法设置Package,使得发送的广播改为显示广播。