android: 接收系统广播
2016-02-03 08:49
721 查看
Android 内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到 各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一 条广播,时间或时区发生改变也会发出一条广播等等。如果想要接收到这些广播,就需要使 用广播接收器,下面我们就来看一下它的具体用法。
5.2.1 动态注册监听网络变化
广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广 播接收器就能够收到该广播,并在内部处理相应的逻辑。注册广播的方式一般有两种,在代 码中注册和在 AndroidManifest.xml 中注册,其中前者也被称为动态注册,后者也被称为静态 注册。
那么该如何创建一个广播接收器呢?其实只需要新建一个类,让它继承自 BroadcastReceiver, 并重写父类的 onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行, 具体的逻辑就可以在这个方法中处理。
那我们就先通过动态注册的方式编写一个能够监听网络变化的程序,借此学习一下广播 接收器的基本用法吧。新建一个 BroadcastTest 项目,然后修改 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 = 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) {
Toast.makeText(context,
"network changes", Toast.LENGTH_SHORT).show();
}
}
}
可以看到,我们在 MainActivity 中定义了一个内部类 NetworkChangeReceiver,这个类 是继承自 BroadcastReceiver 的,并重写了父类的 onReceive()方法。这样每当网络状态发生变 化时,onReceive()方法就会得到执行,这里只是简单地使用 Toast 提示了一段文本信息。
然后观察 onCreate()方法,首先我们创建了一个 IntentFilter 的实例,并给它添加了一个 值为 android.net.conn.CONNECTIVITY_CHANGE 的 action,为什么要添加这个值呢?因为 当网络状态发生变化时,系统发出的正是一条值为 android.net.conn.CONNECTIVITY_ CHANGE 的广播,也就是说我们的广播接收器想要监听什么广播,就在这里添加相应的 action 就行了。接下来创建了一个 NetworkChangeReceiver 的实例,然后调用 registerReceiver() 方法进行注册,将 NetworkChangeReceiver 的实例和
IntentFilter 的实例都传了进去,这样 NetworkChangeReceiver 就会收到所有值为 android.net.conn.CONNECTIVITY_CHANGE 的广 播,也就实现了监听网络变化的功能。
最后要记得,动态注册的广播接收器一定都要取消注册才行,这里我们是在 onDestroy()方法中通过调用 unregisterReceiver()方法来实现的。 整体来说,代码还是非常简单的,现在运行一下程序。首先你会在注册完成的时候收到一条广播,然后按下 Home 键回到主界面(注意不能按 Back 键,否则 onDestroy()方法会执 行),接着按下 Menu
键→System settings→Data usage 进入到数据使用详情界面,然后尝试着 开关 Mobile
Data 来启动和禁用网络,你就会看到有 Toast
提醒你网络发生了变化。
不过只是提醒网络发生了变化还不够人性化,最好是能准确地告诉用户当前是有网络还
是没有网络,因此我们还需要对上面的代码进行进一步的优化。修改 MainActivity 中的代码, 如下所示:
public class MainActivity extends
Activity {
……
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();
}
}
}
}
在 onReceive()方法中,首先通过 getSystemService()方法得到了 ConnectivityManager 的 实例,这是一个系统服务类,专门用于管理网络连接的。然后调用它getActiveNetworkInfo() 方法可以得到 NetworkInfo 的实例,接着调用 NetworkInfo 的 isAvailable()方法,就可以判断 出当前是否有网络了,最后我们还是通过 Toast
的方式对用户进行提示。
另外,这里有非常重要的一点需要说明,Android 系统为了保证应用程序的安全性做了 规定,如果程序需要访问一些系统的关键性信息,必须在配置文件中声明权限才可以,否则
程 序 将 会 直 接 崩 溃 , 比 如 这 里 查 询 系 统 的 网 络 状 态 就 是 需 要 声 明 权 限 的 。 打 开 AndroidManifest.xml 文件,在里面加入如下权限就可以查询系统网络状态了:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.broadcasttest"
android:versionCode="1" android:versionName="1.0"
>
<uses-sdk
android:minSdkVersion="14" android:targetSdkVersion="19"
/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
……
</manifest>
访问 http://developer.android.com/reference/android/Manifest.permission.html 可以查看 Android
系统所有可声明的权限。
现在重新运行程序,然后按下 Home 键→按下 Menu
键→System settings→Data usage 进 入到数据使用详情界面,关闭 Mobile Data 会弹出无网络可用的提示,如图 5.3 所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084823304-906498381.jpg)
图 5.3
然后重新打开 Mobile
Data 又会弹出网络可用的提示,如图 5.4 所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084830913-1720377396.jpg)
图 5.4
5.2.2 静态注册实现开机启动
动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是 它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在 onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下就能接收到广播 呢?这就需要使用静态注册的方式了。
这里我们准备让程序接收一条开机广播,当收到这条广播时就可以在 onReceive()方法里 执行相应的逻辑,从而实现开机启动的功能。新建一个 BootCompleteReceiver 继承自 BroadcastReceiver,代码如下所示:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
}
}
可以看到,这里不再使用内部类的方式来定义广播接收器,因为稍后我们需要在 AndroidManifest.xml 中将这个广播接收器的类名注册进去。在 onReceive()方法中,还是简单 地使用 Toast 弹出一段提示信息。
然后修改 AndroidManifest.xml 文件,代码如下所示:
<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.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
……
<receiver android:name=".BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
终于,<application>标签内出现了一个新的标签<receiver>,所有静态注册的广播接收器
都是在这里进行注册的。它的用法其实和<activity>标签非常相似,首先通过 android:name 来指定具体注册哪一个广播接收器,然后在<intent-filter>标签里加入想要接收的广播就行了, 由于 Android 系统启动完成后会发出一条值为 android.intent.action.BOOT_COMPLETED 的广 播,因此我们在这里添加了相应的 action。
另外,监听系统开机广播也是需要声明权限的,可以看到,我们使用<uses-permission>标签又加入了一条 android.permission.RECEIVE_BOOT_COMPLETED 权限。 现在重新运行程序后,我们的程序就已经可以接收开机广播了,首先打开到应用程序管理界面来查看一下当前程序所拥有的权限。在桌面按下 Menu 键→System settings→Apps,然 后点击 BroadcastTest,如图 5.5
所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084906413-1425255529.jpg)
图 5.5
可以看到,我们的程序目前拥有访问网络状态和开机自动启动的权限。然后将模拟器关
闭并重新启动,在启动完成之后就会收到开机广播了,如图 5.6 所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084915194-1646327281.jpg)
图 5.6
到目前为止,我们在广播接收器的 onReceive()方法中都只是简单地使用 Toast 提示了一 段文本信息,当你真正在项目中使用到它的时候,就可以在里面编写自己的逻辑。需要注意 的是,不要在 onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收 器中是不允许开启线程的,当 onReceive()方法运行了较长时间而没有结束时,程序就会报错。
因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或
者启动一个服务等.
5.2.1 动态注册监听网络变化
广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广 播接收器就能够收到该广播,并在内部处理相应的逻辑。注册广播的方式一般有两种,在代 码中注册和在 AndroidManifest.xml 中注册,其中前者也被称为动态注册,后者也被称为静态 注册。
那么该如何创建一个广播接收器呢?其实只需要新建一个类,让它继承自 BroadcastReceiver, 并重写父类的 onReceive()方法就行了。这样当有广播到来时,onReceive()方法就会得到执行, 具体的逻辑就可以在这个方法中处理。
那我们就先通过动态注册的方式编写一个能够监听网络变化的程序,借此学习一下广播 接收器的基本用法吧。新建一个 BroadcastTest 项目,然后修改 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 = 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) {
Toast.makeText(context,
"network changes", Toast.LENGTH_SHORT).show();
}
}
}
可以看到,我们在 MainActivity 中定义了一个内部类 NetworkChangeReceiver,这个类 是继承自 BroadcastReceiver 的,并重写了父类的 onReceive()方法。这样每当网络状态发生变 化时,onReceive()方法就会得到执行,这里只是简单地使用 Toast 提示了一段文本信息。
然后观察 onCreate()方法,首先我们创建了一个 IntentFilter 的实例,并给它添加了一个 值为 android.net.conn.CONNECTIVITY_CHANGE 的 action,为什么要添加这个值呢?因为 当网络状态发生变化时,系统发出的正是一条值为 android.net.conn.CONNECTIVITY_ CHANGE 的广播,也就是说我们的广播接收器想要监听什么广播,就在这里添加相应的 action 就行了。接下来创建了一个 NetworkChangeReceiver 的实例,然后调用 registerReceiver() 方法进行注册,将 NetworkChangeReceiver 的实例和
IntentFilter 的实例都传了进去,这样 NetworkChangeReceiver 就会收到所有值为 android.net.conn.CONNECTIVITY_CHANGE 的广 播,也就实现了监听网络变化的功能。
最后要记得,动态注册的广播接收器一定都要取消注册才行,这里我们是在 onDestroy()方法中通过调用 unregisterReceiver()方法来实现的。 整体来说,代码还是非常简单的,现在运行一下程序。首先你会在注册完成的时候收到一条广播,然后按下 Home 键回到主界面(注意不能按 Back 键,否则 onDestroy()方法会执 行),接着按下 Menu
键→System settings→Data usage 进入到数据使用详情界面,然后尝试着 开关 Mobile
Data 来启动和禁用网络,你就会看到有 Toast
提醒你网络发生了变化。
不过只是提醒网络发生了变化还不够人性化,最好是能准确地告诉用户当前是有网络还
是没有网络,因此我们还需要对上面的代码进行进一步的优化。修改 MainActivity 中的代码, 如下所示:
public class MainActivity extends
Activity {
……
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();
}
}
}
}
在 onReceive()方法中,首先通过 getSystemService()方法得到了 ConnectivityManager 的 实例,这是一个系统服务类,专门用于管理网络连接的。然后调用它getActiveNetworkInfo() 方法可以得到 NetworkInfo 的实例,接着调用 NetworkInfo 的 isAvailable()方法,就可以判断 出当前是否有网络了,最后我们还是通过 Toast
的方式对用户进行提示。
另外,这里有非常重要的一点需要说明,Android 系统为了保证应用程序的安全性做了 规定,如果程序需要访问一些系统的关键性信息,必须在配置文件中声明权限才可以,否则
程 序 将 会 直 接 崩 溃 , 比 如 这 里 查 询 系 统 的 网 络 状 态 就 是 需 要 声 明 权 限 的 。 打 开 AndroidManifest.xml 文件,在里面加入如下权限就可以查询系统网络状态了:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.broadcasttest"
android:versionCode="1" android:versionName="1.0"
>
<uses-sdk
android:minSdkVersion="14" android:targetSdkVersion="19"
/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
……
</manifest>
访问 http://developer.android.com/reference/android/Manifest.permission.html 可以查看 Android
系统所有可声明的权限。
现在重新运行程序,然后按下 Home 键→按下 Menu
键→System settings→Data usage 进 入到数据使用详情界面,关闭 Mobile Data 会弹出无网络可用的提示,如图 5.3 所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084823304-906498381.jpg)
图 5.3
然后重新打开 Mobile
Data 又会弹出网络可用的提示,如图 5.4 所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084830913-1720377396.jpg)
图 5.4
5.2.2 静态注册实现开机启动
动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是 它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在 onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下就能接收到广播 呢?这就需要使用静态注册的方式了。
这里我们准备让程序接收一条开机广播,当收到这条广播时就可以在 onReceive()方法里 执行相应的逻辑,从而实现开机启动的功能。新建一个 BootCompleteReceiver 继承自 BroadcastReceiver,代码如下所示:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
}
}
可以看到,这里不再使用内部类的方式来定义广播接收器,因为稍后我们需要在 AndroidManifest.xml 中将这个广播接收器的类名注册进去。在 onReceive()方法中,还是简单 地使用 Toast 弹出一段提示信息。
然后修改 AndroidManifest.xml 文件,代码如下所示:
<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.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
……
<receiver android:name=".BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
终于,<application>标签内出现了一个新的标签<receiver>,所有静态注册的广播接收器
都是在这里进行注册的。它的用法其实和<activity>标签非常相似,首先通过 android:name 来指定具体注册哪一个广播接收器,然后在<intent-filter>标签里加入想要接收的广播就行了, 由于 Android 系统启动完成后会发出一条值为 android.intent.action.BOOT_COMPLETED 的广 播,因此我们在这里添加了相应的 action。
另外,监听系统开机广播也是需要声明权限的,可以看到,我们使用<uses-permission>标签又加入了一条 android.permission.RECEIVE_BOOT_COMPLETED 权限。 现在重新运行程序后,我们的程序就已经可以接收开机广播了,首先打开到应用程序管理界面来查看一下当前程序所拥有的权限。在桌面按下 Menu 键→System settings→Apps,然 后点击 BroadcastTest,如图 5.5
所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084906413-1425255529.jpg)
图 5.5
可以看到,我们的程序目前拥有访问网络状态和开机自动启动的权限。然后将模拟器关
闭并重新启动,在启动完成之后就会收到开机广播了,如图 5.6 所示。
![](http://images2015.cnblogs.com/blog/15207/201602/15207-20160203084915194-1646327281.jpg)
图 5.6
到目前为止,我们在广播接收器的 onReceive()方法中都只是简单地使用 Toast 提示了一 段文本信息,当你真正在项目中使用到它的时候,就可以在里面编写自己的逻辑。需要注意 的是,不要在 onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收 器中是不允许开启线程的,当 onReceive()方法运行了较长时间而没有结束时,程序就会报错。
因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或
者启动一个服务等.
相关文章推荐
- android: 广播机制
- android:各种访问权限Permission
- Android属性动画完全解析(中)
- Android属性动画完全解析(上)
- Android中将布局文件/View添加至窗口过程分析
- Android客户端与服务器端交互数据之json解析
- 《Android源码设计模式》读书笔记 (4) 第4章 原型模式
- A1.Android开发环境配置
- Maven学习之 在Android项目上启用maven
- Android项目使用support v7时遇到的各种问题
- 关于Android开发中的证书和密钥等问题
- 【Android开发小记--6】动画--属性动画以及Fragment切换动画(3D)
- akira的android豆知识160202
- Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载
- android程序的断点单步调试步骤
- 【转】android JNI
- 【转】Android JNI编程—JNI基础
- 安卓手机虚拟按键
- 【转】Android与JNI(二) -- 不错
- 【转】 Android的NDK开发(1)————Android JNI简介与调用流程