11.5. NetworkReceiver
11.5.NetworkReceiver
现在,我们的Service已经可以跟随系统启动,并每分钟定时尝试连接服务端以获取数据。但这样的设计存在一个问题,那就是即使设备没有联网,程序仍定时试图连接服务端抓取数据,这样只会无谓地浪费电能。假如你正在坐一趟国际航班,上面没有网络连接,几个小时下来不难想像这将多么浪费。电能与网络连接都不是永久的,我们应尽量减少无谓的操作。
一个解决方案是监听网络的连接情况,并由它来决定Service的启动关闭。系统会在网络连接情况发生变化时发送一条Intent,另外也有系统服务可用于查看当前的网络连接情况。
接下来,我们创建一个新的Receiver:NetworkReceiver。步骤同前面一样,新建一个Java类,并继承BroadcastReceiver,然后在Manifest文件中注册它。
例 11.8. NetworkReceiver.java
package com.marakana.yamba6;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.util.Log;
public class NetworkReceiver extends BroadcastReceiver { //
public static final String TAG = "NetworkReceiver";
@Override
public void onReceive(Context context, Intent intent) {
boolean isNetworkDown = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); //
if (isNetworkDown) {
Log.d(TAG, "onReceive: NOT connected, stopping UpdaterService");
context.stopService(new Intent(context, UpdaterService.class)); //
} else {
Log.d(TAG, "onReceive: connected, starting UpdaterService");
context.startService(new Intent(context, UpdaterService.class)); //
}
}
}
- 同前面一样,它也是BroadcastReceiver的子类。
- 系统会在发送广播时,在这条Intent中加入一组附加数据,表示网络的连接情况,也就是ConnectivityManager.EXTRA_NO_CONNECTIVITY所对应的布尔值。前面我们曾为自己的Intent加入附加数据,在这里相反,只管取出数据即可。若这个值为true,则表示网络断开。
- 如果网络断开,则向UpdaterService发送一条Intent,令它停止。通过系统传入的Context对象。
- 如果网络连接,则启动UpdaterService,与前面相反。
Note:
在Activity或者Service中,我们可以直接调用startActivity()、startService()、stopService()等方法。这是因为Activity与Service都是Context的子类,它们自身就是一个Context对象。但BroadcastReceiver并不是Context的子类,因此发送Intent,仍需通过系统传递的Context对象。
新的Receiver已经编写完毕,接下来将它注册到Manifest文件。
例 11.9. AndroidManifest.xml: 在<application>标签之下
...
<receiver android:name=".NetworkReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
...
我们还需要更新应用程序所需的权限。在系统中,网络连接状况是受保护的信息,要获取它,我们需要用户赋予应用程序以专门的权限。
例 11.10. AndroidManifest.xml: 在<manifest>标签之下
...
<uses-permission android:name="android.permission.INTERNET" /> <!-- -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- -->
...
- 访问网络所需的权限。这是在第六章Android用户界面中定义的。如果没有这项权限,应用程序就无法连接到网络。
- 监视系统启动所需的权限。如果没有这项权限,应用程序就无法捕获系统启动这一事件,而且没有任何错误提示。
- 监视网络连接情况所需的权限。与上面相似,如果没有这项权限,应用程序就无法获知网络连接情况的变化,而且没有任何错误提示。