1. 广播机制简介
为什么说Android中的广播机制灵活呢?这是因为Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己所关心的广播内容,这些广播可能是来自系统的,也可能是来自于其他应用程序的。Android提供了一套完整的API,允许应用程序自由地发送和接收广播。
Android中的广播主要分为两种类型,标准广播和有序广播。
标准广播是一种完全异步执行的广播。在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此他们之间没有任何先后顺序而言。这种广播的效率比较高,但同时也意味着它是无法被截断的。
有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所有此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法接收到广播消息了。
2. 接收系统广播
2.1 动态注册监听网络变化
public class MainActivity extends Activity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter); //注册广播
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver); //取消注册广播
}
class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectionManager = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isAvailable()) {
Toast.makeText(context, "network is available",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "network is unavailable",
Toast.LENGTH_SHORT).show();
}
}
}
}
}
2.2 静态注册实现开机启动
新建一个BootCompleteReceiver,如下:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
}
}
在AndroidManifest文件中注册:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver android:name=".BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</receiver>
</application>
</manifest>
需要注意的是:不要在onReceiver方法中添加过多地饿逻辑或者进行任何的耗时操作,因为在广播接收者中是不允许开启线程的,当onReceiver方法运行了较长时间而没有结束时,程序就会报错,因此广播接收者更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动一个服务等。最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉,耗时的较长的工作最好放在服务中完成
3. 发送自定义广播
3.1 发送标准广播
新建一个MyBroadcastReceiver继承自BroadcastReceiver,代码如下所示:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceive",
Toast.LENGTH_SHORT).show();
}
}
在AndroidManifest文件中对这个广播接收者进行注册:
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
发送广播:
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
3.2 发送有序广播
广播是一种跨进程的通信方式,因此在我们应用程序内发出的广播,其他应用程序也是能接收到的。
新建一个工程,创建一个广播接收者AnotherBroadcastReceiver,如下所示:
public class AnotherBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in AnotherBroadcastReceiver",
Toast.LENGTH_SHORT).show();
abortBroadcast();
}
}
在AndroidManifest文件中注册
<receiver
android:name=".AnotherBroadcastReceiver"
>
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
AnotherBroadcastReceiver能接收到com.example.broadcasttest.MY_BROADCAST这条广播。
发送有序广播:
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent);
设置广播接收优先级:
<receiver android:name=".MyBroadcastReceiver" android:priority="100"> //广播优先级
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
我们通过android:priority属性给广播接收者设置了优先级,优先级比较高的广播接收者就可以先收到广播。这里将MyBroadcastReceiver的优先级设为100,以保证它一定会在AnotherBroadcastReceiver之前收到广播。
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceive",
Toast.LENGTH_SHORT).show();
abortBroadcast();//截断广播
}
}
4. 使用本地广播
本地广播只能在应用程序的内部进行传递,并且广播接收者也只能接收来自本应用程序发出的广播。
public class MainActivity extends Activity {
private IntentFilter intentFilter;
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 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();
}
}
}
需要注意的是,本地广播是无法通过静态注册的方式来接收的,因为静态注册主要就是为了让程序在未启动的情况下也能收到广播,而发送本地广播时,我们的程序肯定是以及启动了,因此完全不需要静态注册的功能。
本地广播的优势:
可以明确地知道正在发送的广播不会离开我们的程序,因此不需要担心数据泄露的问题
其他的程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患
发送本地广播比发送系统全局广播更加高效