广播机制简介
广播(Broadcast)是在组件之间传播数据(Intent)的一种机制;这些组件可以位于同一进程或者不同的进程中,这样它就像Binder机制一样,起到通信的作用; 广播机制非常灵活,每个应用程序都可以对自己感兴趣的广播进行注册,这个程序也只会收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的。 为什么需要广播机制呢?广播机制,本质上它就是一种组件间的通信方式,如果是两个组件位于不同的进程当中,那么可以用Binder机制来实现,如果两个组件是在同一个进程中,那么它们之间可以用来通信的方式就更多了,广播机制和Binder机制不一样的地方在于,广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。
广播主要可以分为两种类型,标准广播和有序广播。
标准广播(Normal broadcasts)
标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎会在同一时刻接收到这条广播消息。这种广播效率比较高,但同时也意味着它是无法被截断的。
有序广播(Ordered broadcasts)
有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕之后,广播才会继续传递。
接收广播
广播接收器可以对自己感兴趣的广播进行注册,当有相应的广播发出时,广播接收器就能够收到该广播,并在内部处理相对应的逻辑。Android系统内置了很多系统级别的广播,可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如, 开机广播,电池电量广播,时间改变广播等。
两种注册广播的方式,动态注册和静态注册
动态注册就是在代码中注册
静态注册就是在AndroidManifest.xml 中注册
创建方式
创建广播接收器只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceiver()方法。当有消息通过广播传递过来时,onReceive()方法就会得到执行。
动态注册网络变化广播
public class MainActivity extends AppCompatActivity {
private NetWorkChangeReceiver netWorkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
netWorkChangeReceiver = new NetWorkChangeReceiver();
//注册广播接收器
registerReceiver(netWorkChangeReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//动态注册广播最后要取消注册
unregisterReceiver(netWorkChangeReceiver);
}
//集成 BroadcastReceiver 内部类
private class NetWorkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isAvailable()) {
Toast.makeText(MainActivity.this, "网络已连接", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "网络不可用", Toast.LENGTH_LONG).show();
}
}
}
}
1、在 IntentFilter 的 addAction() 方法中添加了一个值为 android.net.conn.CONNECTIVITY_CHANGE 的 action,用于接收系统对网络状态改变广播。
2、调用 registerReceiver() 方法对广播接收器进行注册,将 BroadcastReceiver 和 IntentFilter 的实例传递进去即可。
3、组件销毁的时候,通过调用 unregisterReceiver() 方法取消注册。
4、修改 NetworkChangeReceiver 的 onReceiver() 方法。
查询网络状态需要声明权限,代码如下:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
动态注册开机广播
动态注册广播接收器可以自由地控制注册与注销,在灵活性方面有很大优势。但是它也存在一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。而静态注册可以让程序在未启动的情况下就能接收到广播。
接收开机广播,接收到广播后在onReceive()方法里执行相应的逻辑,从而实现开机启动的功能。
代码如下 :
public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "接收到开机广播", Toast.LENGTH_LONG).show();
}
}
AndroidManifest 配置如下:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<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=".BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
注意:不要再 onReceive() 方法中添加过多的逻辑或者进行任何耗时的操作,当onReceive()方法运行了较长时间而没有结束时,程序就会出现ANR(Application Not Responding)。广播接收器更多是扮演打开其他组件的角色,比如创建一条状态栏通知,或者启动一个服务。
发送自定义广播
标准广播
首先定义一个广播接收器来准备接收广播,并在XML中对这个广播接收器进行注册:
代码如下
CustomReceiver 广播接收器
public class CustomReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String info = intent.getStringExtra("info");
Toast.makeText(context, info, Toast.LENGTH_LONG).show();
}
在 AndroidManifest.xml 注册广播接收器:
<receiver android:name=".CustomReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.owen.broadcast"/>
</intent-filter>
</receiver>
Activity 中发送广,播首先构建一个Intent对象,并把要发送的广播的值传入,然后调用 Context 的 sendBroadcast()方法将广播发送出去,这样监听 com.owen.broadcast 这条广播的广播接收器能接收到。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.send_broadcast).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.owen.broadcast");
intent.putExtra("info", "Hi, My Dear brother");
sendBroadcast(intent);
}
});
}
}
有序广播:
广播是一种可以跨进程的通信方式。因此在我们应用程序内发出的广播,其他的应用程序也可以收到。有序广播的接收是有先后顺序的,前面的广播接收器还可以将广播截断,阻止其继续传播。
如果要设定广播接收器的先后顺序,可以在注册的时候进行设定,在 AndroidManifest 中在的元素中,通过android:priority 属性给广播接收器设置优先级,数值越大的优先级越高,优先级越高的就可以先收到广播。如果在 BroadcastReceiver 的子类方法 onReceiver()中调用了 abortBroadcast()方法,就表示将这条广播截断,后面的广播接收器将无法再接收到这条广播。
发送有序广播只需要将 sendBroadcast()方法改成 sendOrderedBroadcast()方法即可。
本地广播
系统广播可以被其他任何程序接收到,这样就很容易引起安全性的问题。比如我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。
为了能够简单地解决广播安全性问题,Android 引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
本地广播的用法并不复杂,主要就是使用了一个LocalBroadcastManager 来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
实现方法如下:
public class MainActivity extends AppCompatActivity {
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.owen.broadcast");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
findViewById(R.id.send_broadcast).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.owen.broadcast");
intent.putExtra("owen", "Hi my local brother");
localBroadcastManager.sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
private class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, intent.getStringExtra("owen"), Toast.LENGTH_LONG).show();
}
}
}
首先通过LocalBroadcastManager 的 getInstance() 方法得到它的一个实例,然后在注册广播接收器的时候调用的是 LocalBroadcastManager 的 registerReceiver()方法,在发送广播的时候调用的是 LocalBroadcastManager 的 sendBroadcast() 方法.