注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/basics/network-ops/managing.html


这节课将讲解如何写一个对使用网络资源具有细粒度控制的应用。如果你的应用要执行很多网络操作,你需要提供用户设置,使得用户可以控制你的应用处理数据的行为,比如你的应用同步数据的频率,是仅在有Wi-Fi连接的情况下上传/下载,在漫游时是否处理数据等。当用户可以进行这些设置时,用户就不太会阻止你的应用访问后台数据了,因为他们能精确地控制应用能处理的数据范围。

有关一些通用的关于如何编写最小化影响电池寿命的应用程序,相关的引导可以阅读:Optimizing Battery LifeTransferring Data Without Draining the Battery


一). 检查设备的网络连接

一个设备可以有许多种网络连接。这节课关注于使用Wi-Fi连接或者移动网络连接。完整的连接类型列表,可以阅读:ConnectivityManager

一般而言,Wi-Fi速度更快。另外移动数量一般按照流量计费,所以会很昂贵。通常的策略是只在有Wi-Fi连接的情况下获取大数据。

在你执行网络操作之前,检查网络的连接状态时一个好的习惯。这可以防止你的应用错误地使用网络连接方式。如果网络连接无法获取,你的应用应该恰当地做出响应。要检查网络连接状态,通常你会使用下列类:

  • ConnectivityManager - 响应网络连接状态的查询。它也在网络连接放生改变时,通知应用。
  • NetworkInfo - 对给定的类型(移动数据或者Wi-Fi)描绘网络接口的状态。

这个代码检测Wi-Fi和移动数据的网络连接。它确定这些网络接口是否可用(网络连接是否可以获取)或者是否已连接(也就是说,网络连接是否存在或者是否可能建立套接字并传输数据):

private static final String DEBUG_TAG = "NetworkStatusExample";
...
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
boolean isWifiConn = networkInfo.isConnected();
networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isMobileConn = networkInfo.isConnected();
Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);

注意,在做决策时不可以仅根据网络是否可获得来进行。应该在每次进行网络操作之间检查isConnected(),因为isConnected()能够处理诸如片状移动网络(flaky mobile networks),飞行模式,以及后台限制的数据。

一个更简洁的方法是检查是否有一个可获得的网络连接接口,如下所示。getActiveNetworkInfo()方法返回一个NetworkInfo实例,它代表它能发现的第一个已连接的网络接口,或者在没有已连接的网络接口时返回null(意味着无法获取一个网络连接):

public boolean isOnline() {
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}

要查询更详细的连接状态,你可以使用NetworkInfo.DetailedState,但一般来说这是不必要的。


二). 管理网络的使用

你可以实现一个用以对应用进行设置的activity,使得用户可以对应用对网络资源的使用进行控制。例如:

  • 你可以只允许用户在连接了Wi-Fi的情况下上传视频;
  • 你可以根据多个标准,如网络可获得否,时间间隔,等等,进行同步(或不进行)。

要写一个支持网络访问和管理网络使用的应用,你的应用需要有相应的权限和intent过滤器。

  • 下面摘录的的配置清单包含下列权限:

  • 你可以声明针对于ACTION_MANAGE_NETWORK_USAGE(该action自Android 4.0开始引入)的intent过滤器,它用来表明你的应用定义了一个可以对数据使用进行控制的activity。ACTION_MANAGE_NETWORK_USAGE展示了对某个特定应用的数据使用管理的设置。当你的应用有允许用户设置网络使用的activity时,你应该为该activity配置此intent过滤器。在样例代码中,该action由SettingsActivity捕获并处理,它显示一个配置界面,让用户来选择何时下载:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.networkusage"
...> <uses-sdk android:minSdkVersion="4"
android:targetSdkVersion="14" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application
...>
...
<activity android:label="SettingsActivity" android:name=".SettingsActivity">
<intent-filter>
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

三). 实现一个配置Activity

如同你所看到的上述清单文件,样例中的activity:SettingsActivity有一个针对于ACTION_MANAGE_NETWORK_USAGE的intent过滤器。SettingsActivity是PreferenceActivity的一个子类。它显示一个配置界面(如图1所示)让用户可以进行下列控制:

  • 是否显示每一个XML源条目的摘要,或仅对每个条目显示其链接;
  • 是否在任何情况下下载XML源,或只在连接了Wi-Fi的情况下。

 

图1. 配置activity

下面的代码是SettingsActivity,注意它实现了OnSharedPreferenceChangeListener。当用户进行了设置的变更时,会激活onSharedPreferenceChanged(),在该方法中会把refreshDisplay变为true,这会导致当用户回到主activity时发生显示刷新:

public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Loads the XML preferences file
addPreferencesFromResource(R.xml.preferences);
} @Override
protected void onResume() {
super.onResume(); // Registers a listener whenever a key changes
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
} @Override
protected void onPause() {
super.onPause(); // Unregisters the listener set in onResume().
// It's best practice to unregister listeners when your app isn't using them to cut down on
// unnecessary system overhead. You do this in onPause().
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
} // When the user changes the preferences selection,
// onSharedPreferenceChanged() restarts the main activity as a new
// task. Sets the refreshDisplay flag to "true" to indicate that
// the main activity should update its display.
// The main activity queries the PreferenceManager to get the latest settings. @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// Sets refreshDisplay to true so that when the user returns to the main
// activity, the display refreshes to reflect the new settings.
NetworkActivity.refreshDisplay = true;
}
}

四). 响应配置变更

当用户在配置界面改变了设置,它会改变应用的行为。在下面的代码片段中,应用在onStart()方法内检查各项设置。如果在设置和设备网络连接之间能够匹配的上(例如,设置是“Wi-Fi”且应用具有一个可使用的Wi-Fi连接),那么应用会下载数据源并刷新页面:

public class NetworkActivity extends Activity {
public static final String WIFI = "Wi-Fi";
public static final String ANY = "Any";
private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest"; // Whether there is a Wi-Fi connection.
private static boolean wifiConnected = false;
// Whether there is a mobile connection.
private static boolean mobileConnected = false;
// Whether the display should be refreshed.
public static boolean refreshDisplay = true; // The user's current network preference setting.
public static String sPref = null; // The BroadcastReceiver that tracks network connectivity changes.
private NetworkReceiver receiver = new NetworkReceiver(); @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Registers BroadcastReceiver to track network connection changes.
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
receiver = new NetworkReceiver();
this.registerReceiver(receiver, filter);
} @Override
public void onDestroy() {
super.onDestroy();
// Unregisters BroadcastReceiver when app is destroyed.
if (receiver != null) {
this.unregisterReceiver(receiver);
}
} // Refreshes the display if the network connection and the
// pref settings allow it. @Override
public void onStart () {
super.onStart(); // Gets the user's network preference settings
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); // Retrieves a string value for the preferences. The second parameter
// is the default value to use if a preference value is not found.
sPref = sharedPrefs.getString("listPref", "Wi-Fi"); updateConnectedFlags(); if(refreshDisplay){
loadPage();
}
} // Checks the network connection and sets the wifiConnected and mobileConnected
// variables accordingly.
public void updateConnectedFlags() {
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
if (activeInfo != null && activeInfo.isConnected()) {
wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
} else {
wifiConnected = false;
mobileConnected = false;
}
} // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
public void loadPage() {
if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
|| ((sPref.equals(WIFI)) && (wifiConnected))) {
// AsyncTask subclass
new DownloadXmlTask().execute(URL);
} else {
showErrorPage();
}
}
... }

五). 检测连接变更

最后一部分内容是关于NetworkReceiverBroadcastReceiver的子类。当设备的网络连接发生了变化,NetworkReceiver会拦截CONNECTIVITY_ACTION,确定当前的连接状态时什么,并相应地将wifiConnectedmobileConnected设置为true/false。产生的结果是,下一次用户回到应用时,应用会仅下载最后一个源并在NetworkActivity.refreshDisplay为true的情况下刷新页面。

配置一个会被不必要地调用的BroadcastReceiver会消耗系统资源。样例中,在onCreate()方法中注册了BroadcastReceiver NetworkReceiver,并在onDestroy()中销毁它。一种更轻量级的解决方法是在清单文件中声明一个 <receiver>。当你这样做了之后,它会在任何时间唤起你的应用,甚至是你已经好几周没有运行该应用了。如果在主activity中注册或注销NetworkReceiver,用户在离开应用后就不会再被唤起了。如果你在清单文件中声明了一个<receiver>,并且你明确的知道你在什么地方会需要它,那么你可以使用setComponentEnabledSetting()在恰当地时机启用或禁用它。

下面是NetworkReceiver:

public class NetworkReceiver extends BroadcastReceiver {   

@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager conn = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = conn.getActiveNetworkInfo(); // Checks the user prefs and the network connection. Based on the result, decides whether
// to refresh the display or keep the current display.
// If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
if (WIFI.equals(sPref) && networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
// If device has its Wi-Fi connection, sets refreshDisplay
// to true. This causes the display to be refreshed when the user
// returns to the app.
refreshDisplay = true;
Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show(); // If the setting is ANY network and there is a network connection
// (which by process of elimination would be mobile), sets refreshDisplay to true.
} else if (ANY.equals(sPref) && networkInfo != null) {
refreshDisplay = true; // Otherwise, the app can't download content--either because there is no network
// connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
// is no Wi-Fi connection.
// Sets refreshDisplay to false.
} else {
refreshDisplay = false;
Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
}
}

【Android Developers Training】 80. 管理网络使用的更多相关文章

  1. 【Android Developers Training】 78. 序言:执行网络操作

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 83. 实现高效网络访问来优化下载

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 14. 序言:管理Activity生命周期

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 79. 连接到网络

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 59. 管理图片存储

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 43. 序言:管理音频播放

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 108. 使用模拟定位进行测试

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 92. 序言:使用同步适配器传输数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 88. 使用备份API

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. Centos程序最小化后,窗口标签都消失找不到窗口的问题

    我是用的centos版本是CentOs 7. 在“顶部面板”或者 “底部面板” 右击选择“添加组件”),如下图所示: 在搜索框里输入“窗口列表”(window list),选中“窗口列表”即可.如下图 ...

  2. Java7中的ForkJoin并发框架初探(上)——需求背景和设计原理

    原文:发表于 2013 年 8 月 26 日 由 三石 0. 处理器发展和需求背景 回想一下并发开发的初衷,其实可以说是有两点,或者说可以从两个方面看. 对于单核的处理器来说,在进行IO操作等比较费时 ...

  3. spring boot --- 初级体验

    Spring boot的介绍我就不多说了,网上可以自己看一下. 它的优点就是:快!适合小白,没有复杂的配置文件. 缺点也很明显:坑有些多, 文档略少,报错有时不知道该如何处理. 下面做个最简单的入门: ...

  4. Linux常用网络测试命令

    Linux常用网络测试命令 1. ifconfig     可以使用ifconfig命令来配置并查看网络接口的配置情况.    例如: (1) 配置eth0的IP地址, 同时激活该设备. #ifcon ...

  5. Updates were rejected because the remote contains work that you do

    每次建立新的仓库,提交的时总会出现这样的错误,真是头疼,...... 直接开始正题,git 提交的步骤: 1. git init //初始化仓库 2. git add .(文件name) //添加文件 ...

  6. iOS开发之 Lottie -- 炫酷的动效

    动效在软件开发中非常常见,炫酷的动画能提升应用的B格,然而由设计师的设计转化成程序猿GG的代码是个非常"痛苦"的过程.对于复杂动画,可能要花费很多时间去研究和实现.Lottie 的 ...

  7. 《算法4》2.1 - 插入排序算法(Insertion Sort), Python实现

    排序算法列表电梯: 选择排序算法:详见 Selection Sort 插入排序算法(Insertion Sort):非常适用于小数组和部分排序好的数组,是应用比较多的算法.详见本文 插入排序算法的语言 ...

  8. js实现导航菜单栏随着屏幕的滚动进行滚动的效果

    $(window).scroll(function () { var $nav = $(".floatingMenu ul li"), length = $nav.length-1 ...

  9. 基于cookie使用过滤器实现客户每次访问自登陆一次

    原创声明:本文为本人原创作品,绝非他处摘取,转载请联系博主 相信大家在各大网站都会遇到,登录时,在登录框出现下次免登陆/一个月免登陆的类似选项,本次博文就是讲解如何实现,在这记录一下,也算是做个备忘录 ...

  10. hdu3622

    hdu3622 题意 每回合给定两个坐标点,可以选择一个放置炸弹,自己决定炸弹的半径,问 n 个回合后,使炸弹半径最小值最大. 分析 存在对立关系:每回合只能选择一个地方放置炸弹.i 表示 第一个位置 ...