Android官方开发文档Training系列课程中文版:网络操作之网络管理
原文地址:http://android.xsoftlab.net/training/basics/network-ops/managing.html
這節課將會學習如何對網絡資源的使用情況擁有更細粒度的控制力。如果應用程序經常執行大量的網絡操作,那么程序應當提供一項設置,以便用戶可以控制應用的數據習性,比如多久同步一次數據,是否只在WIFI情況下上傳下載數據,是否使用移動數據流量等等。隨著這些設置能力的提供,用戶可以設置應用在接近網絡流量限制的情況下禁止應用再次訪問網絡,因為用戶可以直接控制應用程序可以使用多少數據流量。
檢測設備的網絡連接狀況
一臺設備擁有多種類型的網絡連接。這節課所關注的是使用WI-FI或者移動數據網絡連接。有關全面的網絡連接類型,請參見ConnectivityManager.
WIFI通常情況下很快,而移動數據通常按量收費,還很昂貴。APP的通常使用策略是在WIFI網絡可用的情況下才去獲取大量的數據。
在執行網絡操作之前,最好是檢查一下網絡的連接狀態。執行網絡狀態檢查,通常會使用到下面的類:
- ConnectivityManager : 可以獲取當前網絡的連接狀況,還可以在網絡連接狀況發生變化時通知應用程序。
- NetworkInfo : 描述了指定類型的網絡接口狀態。
下面的代碼測試了WIFI及移動數據的連接狀態。它會檢查這些網絡接口是否可用及是否已連接:
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()會處理這些狀態:移動網絡信號不好、飛行模式或者受限的后臺數據。
有一種更簡明的方式可以用來檢查網絡接口是否可用:getActiveNetworkInfo()方法會返回一個NetworkInfo的實例,這個對象代表了所能搜索到的第一個已連接的網絡接口,如果沒有搜索到任何網絡連接則會返回null,null代表了互聯網絡連接不餓用。
public boolean isOnline() {ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();return (networkInfo != null && networkInfo.isConnected()); }你可以使用NetworkInfo.DetailedState查詢更細粒度的網絡狀態,不過很少會被用到。
管理網絡的使用
可以通過實現一個參數設置的Activity來讓用戶控制網絡資源的使用。
- 你可能只允許用戶在WIFI網絡狀態下才可以上傳視頻資源。
- 你可能要允許用戶設置在指定的條件下才去同步數據,比如:網絡可用狀態下,或者隔多長時間等等。
為了使APP可以支持網絡的訪問及網絡使用的管理,那么清單文件中必須包含以下權限以及意圖過濾器:
清單文件應當包含以下權限:
- android.permission.INTERNET 允許應用程序可以訪問網絡插口(Socket)。
- android.permission.ACCESS_NETWORK_STATE 允許應用程序可以訪問網絡信息。
你可以通過聲明ACTION_MANAGE_NETWORK_USAGE的意圖過濾器來指明當前的Activity提供了控制數據使用策略的功能。當應用中含有允許用戶管理網絡數據使用策略的Activity時,應當聲明該意圖過濾器。在這里的示例程序中,這個行為被SettingsActivity所處理,這個Activity允許用戶決定什么時候開始下載。
實現一個參數配置Activity
正如你在上面所看到的,SettingsActivity的意圖過濾器含有一個ACTION_MANAGE_NETWORK_USAGE的行為,SettingsActivity是PreferenceActivity的子類,它的展示效果如下:
下面是SettingsActivity的代碼,注意它實現了OnSharedPreferenceChangeListener接口。每當用戶更改了參數,系統會調用onSharedPreferenceChanged()方法,該方法內將refreshDisplay設置為true,這是因為當用戶返回到主界面是需要刷新界面。
public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Loads the XML preferences fileaddPreferencesFromResource(R.xml.preferences);}@Overrideprotected void onResume() {super.onResume();// Registers a listener whenever a key changes getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);}@Overrideprotected 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.@Overridepublic 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;} }響應參數的變更
當用戶更改了參數時,這個行為會使APP的習性也跟著發生了變化。在下面的代碼段中,APP會在onStart()方法中檢查參數配置,如果在設備的當前連接狀態與設置之間有相匹配的,那么APP將會下載信息,并刷新界面。
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();@Overridepublic 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.@Overridepublic void onStart () {super.onStart(); // Gets the user's network preference settingsSharedPreferences 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 subclassnew DownloadXmlTask().execute(URL);} else {showErrorPage();}} ...}監聽連接變化
最后一個問題就是BroadcastReceiver的子類NetworkReceiver。當設備的網絡連接發生變化時,NetworkReceiver會攔截CONNECTIVITY_ACTION的行為,這個行為用于檢查當前是哪種網絡連接狀態,并會相應的將wifiConnected和mobileConnected設置為true或者false。那么在NetworkActivity.refreshDisplay設置為true時,那么APP會只下載最近一次的資源。
設置的廣播監聽器需要在系統不需要的情況下解除注冊。示例應用中在onCreate()方法中將NetworkReceiver注冊到系統,在onDestroy()方法中將其注銷。這比在清單文件中注冊更為輕量。當在清單文件中聲明了廣播接收器,系統會在任何時候調用該接收器,甚至是很久都沒有啟動過。在Activity中注冊與注銷廣播接收器,可以確保用戶在離開APP后系統不會再調用廣播接收器。如果在清單文件中注冊了廣播接收器,那么你必須清楚在什么地方需要它,你可以適當的使用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官方开发文档Training系列课程中文版:网络操作之网络管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VS Code HtmlFindClas
- 下一篇: IDEA解决Maven项目编译后clas