1 page.title=Managing Network Usage 2 parent.title=Performing Network Operations 3 parent.link=index.html 4 5 trainingnavtop=true 6 7 previous.title=Connecting to the Network 8 previous.link=connecting.html 9 next.title=Parsing XML Data 10 next.link=xml.html 11 12 @jd:body 13 14 <div id="tb-wrapper"> 15 <div id="tb"> 16 17 <h2>This lesson teaches you to</h2> 18 <ol> 19 <li><a href="#check-connection">Check a Device's Network Connection</a></li> 20 <li><a href="#manage-usage">Manage Network Usage</a></li> 21 <li><a href="#prefs">Implement a Preferences Activity</a></li> 22 <li><a href="#pref-change">Respond to Preference Changes</a></li> 23 <li><a href="#detect-changes">Detect Connection Changes</a></li> 24 </ol> 25 <h2>You should also read</h2> 26 <ul> 27 <li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li> 28 <li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li> 29 <li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li> 30 </ul> 31 32 <h2>Try it out</h2> 33 34 <div class="download-box"> 35 <a href="{@docRoot}shareables/training/NetworkUsage.zip" 36 class="button">Download the sample</a> 37 <p class="filename">NetworkUsage.zip</p> 38 </div> 39 40 </div> 41 </div> 42 43 <p>This lesson describes how to write applications that have fine-grained 44 control over their usage of network resources. If your application performs a 45 lot of network operations, you should provide user settings that allow users 46 to control your apps data habits, such as how often your app syncs data, 47 whether to perform uploads/downloads only when on Wi-Fi, whether to use data 48 while roaming, and so on. With these controls available to them, users are much 49 less likely to disable your apps access to background data when they approach their 50 limits, because they can instead precisely control how much data your app 51 uses.</p> 52 53 <p>For general guidelines on how to write apps that minimize the battery life 54 impact of downloads and network connections, see 55 <a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a> 56 and <a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a>. 57 58 <h2 id="check-connection">Check a Device's Network Connection</h2> 59 60 <p>A device can have various types of network connections. This lesson 61 focuses on using either a Wi-Fi or a mobile network connection. For the full 62 list of possible network types, see {@link android.net.ConnectivityManager}.<p> 63 64 <p>Wi-Fi is typically faster. Also, mobile data is often metered, which can get 65 expensive. 66 A common strategy for apps is to only fetch large data 67 if a Wi-Fi network is available.</p> 68 69 <p>Before you perform network operations, it's good practice to check the state of 70 network connectivity. Among other things, this could prevent your app from inadvertently using 71 the wrong radio. If a network connection is unavailable, your application 72 should respond gracefully. To check the network connection, you typically use 73 the following classes:</p> 74 75 <ul> 76 77 <li>{@link android.net.ConnectivityManager}: Answers queries about the state 78 of network connectivity. It also notifies applications when network 79 connectivity changes. </li> 80 81 <li>{@link android.net.NetworkInfo}: Describes the status of a network 82 interface of a given type (currently either Mobile or Wi-Fi). 83 </li> 84 85 </ul> 86 87 88 89 <p>This code snippet tests network connectivity for Wi-Fi and mobile. It 90 determines whether these network interfaces are available (that is, whether 91 network connectivity is possible) and/or connected (that is, whether network 92 connectivity exists and if it is possible to establish sockets and pass 93 data): </p> 94 95 <pre> 96 private static final String DEBUG_TAG = "NetworkStatusExample"; 97 ... 98 ConnectivityManager connMgr = (ConnectivityManager) 99 getSystemService(Context.CONNECTIVITY_SERVICE); 100 NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 101 boolean isWifiConn = networkInfo.isConnected(); 102 networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); 103 boolean isMobileConn = networkInfo.isConnected(); 104 Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn); 105 Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn); 106 </pre> 107 108 <p>Note that you should not base decisions on whether a network is 109 "available." You should always check {@link 110 android.net.NetworkInfo#isConnected isConnected()} before performing network 111 operations, since {@link android.net.NetworkInfo#isConnected isConnected()} 112 handles cases like flaky mobile networks, airplane mode, and restricted 113 background data.</p> 114 115 <p>A more concise way of checking whether a network interface is available is as 116 follows. The method {@link 117 android.net.ConnectivityManager#getActiveNetworkInfo() getActiveNetworkInfo()} 118 returns a{@link android.net.NetworkInfo} instance representing the first 119 connected network interface it can find, or<code>null</code>if none of the 120 interfaces is connected (meaning that an 121 internet connection is not available):</p> 122 123 <pre> 124 public boolean isOnline() { 125 ConnectivityManager connMgr = (ConnectivityManager) 126 getSystemService(Context.CONNECTIVITY_SERVICE); 127 NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); 128 return (networkInfo != null && networkInfo.isConnected()); 129 } </pre> 130 131 <p>To query more fine-grained state you can use {@link 132 android.net.NetworkInfo.DetailedState}, but this should seldom be necessary.</p> 133 134 135 <h2 id="manage-usage">Manage Network Usage</h2> 136 137 <p>You can implement a preferences activity that gives users explicit control 138 over your app's usage of network resources. For 139 example:</p> 140 141 <ul> 142 143 <li>You might allow users to upload videos only when the device is connected to a 144 Wi-Fi network.</li> 145 146 <li>You might sync (or not) depending on specific criteria such as network 147 availability, time interval, and so on.</li> 148 149 </ul> 150 151 <p>To write an app that supports network access and managing 152 network usage, your manifest must have the right permissions and 153 intent filters. 154 </p> 155 156 <ul> 157 <li>The manifest excerpted below includes the following permissions: 158 <ul> 159 160 <li>{@link android.Manifest.permission#INTERNET 161 android.permission.INTERNET}—Allows applications to open network 162 sockets.</li> 163 164 <li>{@link android.Manifest.permission#ACCESS_NETWORK_STATE 165 android.permission.ACCESS_NETWORK_STATE}—Allows applications to access 166 information about networks.</li> 167 168 </ul> 169 </li> 170 171 <li>You can declare the intent filter for the 172 {@link android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} action (introduced in 173 Android 4.0) to indicate that your application defines an activity that offers 174 options to control data usage. {@link 175 android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} shows settings for managing 176 the network data usage of a specific application. When your app has a settings activity 177 that allows users to control network usage, you should declare this intent filter for that activity. 178 In the sample application, this action is handled by the class 179 <code>SettingsActivity</code>, which displays a preferences UI to let users 180 decide when to download a feed.</li> 181 182 </ul> 183 184 185 <pre> 186 <?xml version="1.0" encoding="utf-8"?> 187 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 188 package="com.example.android.networkusage" 189 ...> 190 191 <uses-sdk android:minSdkVersion="4" 192 android:targetSdkVersion="14" /> 193 194 <uses-permission android:name="android.permission.INTERNET" /> 195 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 196 197 <application 198 ...> 199 ... 200 <activity android:label="SettingsActivity" android:name=".SettingsActivity"> 201 <intent-filter> 202 <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> 203 <category android:name="android.intent.category.DEFAULT" /> 204 </intent-filter> 205 </activity> 206 </application> 207 </manifest> 208 </pre> 209 210 <h2 id="prefs">Implement a Preferences Activity</h2> 211 212 <p>As you can see in the manifest excerpt above, the sample app's activity 213 <code>SettingsActivity</code> has an intent filter for the {@link 214 android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} action. 215 <code>SettingsActivity</code> is a subclass of {@link 216 android.preference.PreferenceActivity}. It displays a preferences screen 217 (shown in figure 1) that 218 lets users specify the following:</p> 219 220 <ul> 221 222 <li>Whether to display summaries for each XML feed entry, or just a link for 223 each entry.</li> 224 225 <li>Whether to download the XML feed if any network connection is available, 226 or only if Wi-Fi is available.</li> 227 228 </ul> 229 230 <img src="{@docRoot}images/training/basics/network-settings1.png" alt="Preferences panel" /> 231 232 <img src="{@docRoot}images/training/basics/network-settings2.png" alt="Setting a network preference" /> 233 <p class="img-caption"><strong>Figure 1.</strong> Preferences activity.</p> 234 235 <p>Here is <code>SettingsActivity</code>. Note that it implements 236 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener OnSharedPreferenceChangeListener}. 237 When a user changes a preference, it fires 238 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged onSharedPreferenceChanged()}, 239 which sets {@code refreshDisplay} to true. This causes the display to refresh when the user 240 returns to the main activity:</p> 241 242 <pre>public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener { 243 244 @Override 245 protected void onCreate(Bundle savedInstanceState) { 246 super.onCreate(savedInstanceState); 247 248 // Loads the XML preferences file 249 addPreferencesFromResource(R.xml.preferences); 250 } 251 252 @Override 253 protected void onResume() { 254 super.onResume(); 255 256 // Registers a listener whenever a key changes 257 getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); 258 } 259 260 @Override 261 protected void onPause() { 262 super.onPause(); 263 264 // Unregisters the listener set in onResume(). 265 // It's best practice to unregister listeners when your app isn't using them to cut down on 266 // unnecessary system overhead. You do this in onPause(). 267 getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); 268 } 269 270 // When the user changes the preferences selection, 271 // onSharedPreferenceChanged() restarts the main activity as a new 272 // task. Sets the the refreshDisplay flag to "true" to indicate that 273 // the main activity should update its display. 274 // The main activity queries the PreferenceManager to get the latest settings. 275 276 @Override 277 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 278 // Sets refreshDisplay to true so that when the user returns to the main 279 // activity, the display refreshes to reflect the new settings. 280 NetworkActivity.refreshDisplay = true; 281 } 282 }</pre> 283 284 <h2 id="pref-change">Respond to Preference Changes</h2> 285 286 <p>When the user changes preferences in the settings screen, it typically has 287 consequences for the app's behavior. In this snippet, the app checks the 288 preferences settings in {@code onStart()}. if there is a match between the setting and 289 the device's network connection (for example, if the setting is {@code "Wi-Fi"} and the 290 device has a Wi-Fi connection), the app downloads the feed and refreshes the 291 display.</p> 292 293 <pre> 294 public class NetworkActivity extends Activity { 295 public static final String WIFI = "Wi-Fi"; 296 public static final String ANY = "Any"; 297 private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest"; 298 299 // Whether there is a Wi-Fi connection. 300 private static boolean wifiConnected = false; 301 // Whether there is a mobile connection. 302 private static boolean mobileConnected = false; 303 // Whether the display should be refreshed. 304 public static boolean refreshDisplay = true; 305 306 // The user's current network preference setting. 307 public static String sPref = null; 308 309 // The BroadcastReceiver that tracks network connectivity changes. 310 private NetworkReceiver receiver = new NetworkReceiver(); 311 312 @Override 313 public void onCreate(Bundle savedInstanceState) { 314 super.onCreate(savedInstanceState); 315 316 // Registers BroadcastReceiver to track network connection changes. 317 IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); 318 receiver = new NetworkReceiver(); 319 this.registerReceiver(receiver, filter); 320 } 321 322 @Override 323 public void onDestroy() { 324 super.onDestroy(); 325 // Unregisters BroadcastReceiver when app is destroyed. 326 if (receiver != null) { 327 this.unregisterReceiver(receiver); 328 } 329 } 330 331 // Refreshes the display if the network connection and the 332 // pref settings allow it. 333 334 @Override 335 public void onStart () { 336 super.onStart(); 337 338 // Gets the user's network preference settings 339 SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); 340 341 // Retrieves a string value for the preferences. The second parameter 342 // is the default value to use if a preference value is not found. 343 sPref = sharedPrefs.getString("listPref", "Wi-Fi"); 344 345 updateConnectedFlags(); 346 347 if(refreshDisplay){ 348 loadPage(); 349 } 350 } 351 352 // Checks the network connection and sets the wifiConnected and mobileConnected 353 // variables accordingly. 354 public void updateConnectedFlags() { 355 ConnectivityManager connMgr = (ConnectivityManager) 356 getSystemService(Context.CONNECTIVITY_SERVICE); 357 358 NetworkInfo activeInfo = connMgr.getActiveNetworkInfo(); 359 if (activeInfo != null && activeInfo.isConnected()) { 360 wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI; 361 mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE; 362 } else { 363 wifiConnected = false; 364 mobileConnected = false; 365 } 366 } 367 368 // Uses AsyncTask subclass to download the XML feed from stackoverflow.com. 369 public void loadPage() { 370 if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected)) 371 || ((sPref.equals(WIFI)) && (wifiConnected))) { 372 // AsyncTask subclass 373 new DownloadXmlTask().execute(URL); 374 } else { 375 showErrorPage(); 376 } 377 } 378 ... 379 380 }</pre> 381 382 <h2 id="detect-changes">Detect Connection Changes</h2> 383 384 <p>The final piece of the puzzle is the {@link 385 android.content.BroadcastReceiver} subclass, <code>NetworkReceiver</code>. When 386 the device's network connection changes, <code>NetworkReceiver</code> intercepts 387 the action {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION}, 388 determines what the network connection status is, and sets the flags 389 <code>wifiConnected</code> and <code>mobileConnected</code> to true/false 390 accordingly. The upshot is that the next time the user returns to the app, the 391 app will only download the latest feed and update the display if 392 <code>NetworkActivity.refreshDisplay</code> is set to <code>true</code>.</p> 393 394 <p>Setting up a BroadcastReceiver that gets called unnecessarily can be a 395 drain on system resources. 396 The sample application registers the 397 {@link android.content.BroadcastReceiver} {@code NetworkReceiver} in 398 {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}, 399 and it unregisters it in 400 {@link android.app.Activity#onDestroy onDestroy()}. This is more lightweight 401 than declaring a {@code <receiver>} in the manifest. When you declare a 402 {@code <receiver>} in the manifest, it can wake up your app at any time, 403 even if you haven't run it for weeks. By registering and unregistering 404 {@code NetworkReceiver} within the main activity, you ensure that the app won't 405 be woken up after the user leaves the app. 406 If you do declare a {@code <receiver>} in the manifest and you know exactly 407 where you need it, you can use 408 {@link android.content.pm.PackageManager#setComponentEnabledSetting setComponentEnabledSetting()} 409 to enable and disable it as appropriate.</p> 410 411 <p>Here is <code>NetworkReceiver</code>:</p> 412 413 <pre>public class NetworkReceiver extends BroadcastReceiver { 414 415 @Override 416 public void onReceive(Context context, Intent intent) { 417 ConnectivityManager conn = (ConnectivityManager) 418 context.getSystemService(Context.CONNECTIVITY_SERVICE); 419 NetworkInfo networkInfo = conn.getActiveNetworkInfo(); 420 421 // Checks the user prefs and the network connection. Based on the result, decides whether 422 // to refresh the display or keep the current display. 423 // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection. 424 if (WIFI.equals(sPref) && networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { 425 // If device has its Wi-Fi connection, sets refreshDisplay 426 // to true. This causes the display to be refreshed when the user 427 // returns to the app. 428 refreshDisplay = true; 429 Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show(); 430 431 // If the setting is ANY network and there is a network connection 432 // (which by process of elimination would be mobile), sets refreshDisplay to true. 433 } else if (ANY.equals(sPref) && networkInfo != null) { 434 refreshDisplay = true; 435 436 // Otherwise, the app can't download content--either because there is no network 437 // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there 438 // is no Wi-Fi connection. 439 // Sets refreshDisplay to false. 440 } else { 441 refreshDisplay = false; 442 Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show(); 443 } 444 }</pre> 445 446