发送广播:使用Intent
接收广播:广播接收器
创建广播接收器:
方法:新建一个类继承自BroadcastReceiver,并重写父类的onReceive( )方法。当有广播接收到的时候,onReceive( )中的逻辑就会得到执行
注册广播:
- 动态注册广播:在代码中注册
- 静态注册广播:在AndroidManifest.xml文件中注册
1. 动态注册广播
例子:实现监听网络变化的功能
修改MainActivity中的代码:
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.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) {
Toast.makeText (context , "network change" , Toast.LENGTH_SHORT).show() ;
}
}
}
效果:当我们开关数据的时候,就会出现提醒 “network change”
解析:
Step 1:首先,我们先创建了一个广播接收器,叫做NetworkChangeReceiver
class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive (Context context , Intent intent) {
Toast.makeText (context , "network change" , Toast.LENGTH_SHORT).show() ;
}
}
可见,NetworkChangeReceiver继承自BroadcastReceiver,并且我们重写了其中的onReceive ( )方法,添加了自己的逻辑—–加了一段Toast提醒
Step 2:创建一个IntentFilter对象
private IntentFilter intentFilter ;
Step 3:为IntenFilter添加action,监听某种广播
(系统网络状态发生变化时候,会发出一条action为”android.net.conn.CONNECTIVITY_CHANGE”)
intentFilter.addAction ("android.net.conn.CONNECTIVITY_CHANGE") ;
Intent和IntentFilter的区别:
初看我也很会混淆Intent和IntentFilter,不知道为什么动态注册广播使用IntentFilter.addAction( )而不使用Intent.addAction( )
Intent
一般用于启动活动,服务,组件,发送广播等等,是一种意图
所以,一个Intent只能有唯一的action,作为它启动的活动,或是组件等的唯一标识符
IntentFilter
顾名思义,是一种过滤器,Intent的过滤器。
它只有被用在动态注册广播中
看着很熟悉吧,在AndroidManifest.xml中,每一个activity中都有一个<intent-filter>的标签,它里面描述了activity的各种属性,action,category,data,可以供Intent来匹配。
发送给应用程序的广播多种多样,十分多,怎么样才可以过滤掉我们不想要的广播呢?靠的就是IntentFilter。使用它的addAction( )方法,可以为它添加过滤的字符(有点类似Logcat中的filter),从而在许多广播中找到我们需要的广播
所以,一个IntentFilter可以有多个action作为过滤标识符
Step 4:创建一个广播接收器的实例(我们Step 1创建好的广播接收器NetworkChangeReceiver)
networkChangeReceiver = new NetworkChangeReceiver () ;
Step 5:注册广播
调用registerReceiver( )方法来注册
registerReceiver (networkChangeReceiver , intentFilter) ;
该方法带有两个参数:
- 第一个参数是广播接收器,描述是广播是谁收到的
- 第二个参数是IntentFilter,描述收到哪些广播
Step 6:在活动销毁时注销广播
我们重写onDestroy( )方法,添加注销广播的代码
调用unregisterReceiver( )方法
@Override
protected void onDestroy () {
super.onDestroy () ;
unregisterReceiver (networkChangeReceiver) ;
}
该方法带有一个参数
- 参数是广播接收器,描述销毁的是哪个广播接收器
优化广播接收器:
显然,只有提醒网络变化很不人性化,应该还要提醒网络是否可用
我们这样修改NetworkChangeReceiver中的onReceive( )方法
@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 (context , "network is available" , Toast.LENGTH_SHORT).show() ;
}
else {
Toast.makeText (context , "network is unavailable" , Toast.LENGTH_SHORT).show () ;
}
}
首先,ConnectivityManager是一个系统服务类,专门管理网络连接。调用getSystemService ( )方法,得到它的实例
通过值为Context.CONNECTIVITY_SERVICE来找到它的实例
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService (Context.CONNECTIVITY_SERVICE) ;
然后,NetworkInfo,从名字上看就知道,这是一个带有网络连接方面信息的对象。我们通过getActiveNetworkInfo( )方法来得到当前的NetworkInfo实例
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo () ;
最后可以通过isAvailable( )方法来得知网络是否可用
networkInfo.isAvailable()
然后,一切看起来万事大吉,今晚吃鸡了,我们开开心心run代码。会很难过地发现,程序崩溃了。这是为什么?
原来是因为Android系统为了保证应用程序的安全性做了规定:如果程序需要访问一些系统的关键信息,必须在配置文件中声明权限才可以,否则程序会直接崩溃。
那么,我们便需要在配置文件,也就是AndroidManifest.xml中作出加入查询网络状态的权限
<manifest
……
>
……
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE">
……
</manifest>
优点:灵活,可以自由地控制注册和注销
缺点:必须要在程序启动之后才能接收广播
2. 静态注册广播
例子:我们让程序接收一条开机广播,然后出现提醒
Step 1:创建一个广播接收器
这里创建广播接收器和动态注册的时候有什么不同呢?动态注册广播,我们采用的是在MainActivity.java中定义了内部类的方式,然后在onCreate( )中使用registerReceiver( )方法来动态注册,随时随地注册。而我们这次是要接收开机广播,程序都还没启动,onCreate( )方法都还没有被调用,显然,内部类已经无法满足我们这次的需求
所以,这次我们新建了一个文件叫BootCompleteReceiver.java,里面是一个新建类继承自Broadcast,然后可以在配置文件中进行注册,从而实现开机启动,接收开机广播的功能
BootCompleteReceiver.java
public BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive (Context context , Intent intent) {
Toast.makeText (context , "Boot Complete" , Toast.LENGTH_SHORT).show();
}
}
Step 2:在配置文件中将广播接收器的类名注册进去
AndroidManifest.xml
<manifest
……
>
……
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED">
……
<application
……
>
……
<receiver android:name = ".BootCompleteReceiver">
<intent-filter>
<action android:name = "android.intent.action.RECEIVE_BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>
开机信息自然也是系统关键信息,所以也需要和网络连接那样声明权限
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED">
然后是注册广播接收器的代码,使用了<receiver>的标签;这个标签里面的android:name属性,指明了类名,说明了是哪个广播接收器;然后是这个标签之间的<intent-filter>标签(动态注册用IntentFilter对象,静态注册用<intent-filter>标签),里面的<action/>标签里的android:name属性指明了可以接收的广播的action属性,开机时系统发出的广播的值是”android.intent.action.BOOT_COMPLETED”,所以这里可以接受的广播的action就是上面这个值
<receiver android:name = ".BootCompleteReceiver">
<intent-filter>
<action android:name = "android.intent.action.RECEIVE_BOOT_COMPLETED"/>
</intent-filter>
</receiver>