1page.title=Managing Network Usage
2parent.title=Performing Network Operations
3parent.link=index.html
4
5trainingnavtop=true
6
7previous.title=Connecting to the Network
8previous.link=connecting.html
9next.title=Parsing XML Data
10next.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"
36class="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
44control over their usage of network resources. If your application performs a
45lot of network operations, you should provide user settings that allow users
46to control your app’s data habits, such as how often your app syncs data,
47whether to perform uploads/downloads only when on Wi-Fi, whether to use data
48while roaming, and so on. With these controls available to them, users are much
49less likely to disable your app’s access to background data when they approach their
50limits, because they can instead precisely control how much data your app
51uses.</p>
52
53<p>For general guidelines on how to write apps that minimize the battery life
54impact of downloads and network connections, see
55<a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a>
56and <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
61focuses on using either a Wi-Fi or a mobile network connection. For the full
62list 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
65expensive.
66A common strategy for apps is to only fetch large data
67if a Wi-Fi network is available.</p>
68
69<p>Before you perform network operations, it's good practice to check the state of
70network connectivity. Among other things, this could prevent your app from inadvertently using
71the wrong radio. If a network connection is unavailable, your application
72should respond gracefully. To check the network connection, you typically use
73the following classes:</p>
74
75<ul>
76
77  <li>{@link android.net.ConnectivityManager}: Answers queries about the state
78of network connectivity. It also  notifies applications when network
79connectivity changes. </li>
80
81  <li>{@link android.net.NetworkInfo}: Describes the status of a network
82interface 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
90determines whether these network interfaces are available (that is, whether
91network connectivity is possible) and/or connected (that is, whether network
92connectivity exists and if it is possible to establish sockets and pass
93data): </p>
94
95<pre>
96private static final String DEBUG_TAG = &quot;NetworkStatusExample&quot;;
97...
98ConnectivityManager connMgr = (ConnectivityManager)
99        getSystemService(Context.CONNECTIVITY_SERVICE);
100NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
101boolean isWifiConn = networkInfo.isConnected();
102networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
103boolean isMobileConn = networkInfo.isConnected();
104Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
105Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);
106</pre>
107
108<p>Note that you should not base decisions on whether a network is
109&quot;available.&quot; You should always check {@link
110android.net.NetworkInfo#isConnected isConnected()} before performing network
111operations, since {@link android.net.NetworkInfo#isConnected isConnected()}
112handles  cases like flaky mobile networks, airplane mode, and restricted
113background data.</p>
114
115<p>A more concise way of checking whether a network interface is available is as
116follows. The method {@link
117android.net.ConnectivityManager#getActiveNetworkInfo() getActiveNetworkInfo()}
118returns a {@link android.net.NetworkInfo} instance representing the first
119connected network interface it can find, or <code>null</code> if none of the
120interfaces is connected (meaning that an
121internet connection is not available):</p>
122
123<pre>
124public 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
132android.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
138over your app's usage of network resources. For
139example:</p>
140
141<ul>
142
143<li>You might allow users to upload videos only when the device is connected to a
144Wi-Fi network.</li>
145
146<li>You might sync (or not) depending on specific criteria such as network
147availability, time interval, and so on.</li>
148
149</ul>
150
151<p>To write an app that supports network access and managing
152network usage, your manifest must have the right permissions and
153intent 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
161android.permission.INTERNET}&mdash;Allows applications to open network
162sockets.</li>
163
164      <li>{@link android.Manifest.permission#ACCESS_NETWORK_STATE
165android.permission.ACCESS_NETWORK_STATE}&mdash;Allows applications to access
166information 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
173Android 4.0) to indicate that your application defines an activity that offers
174options to control data usage. {@link
175android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} shows settings for managing
176the network data usage of a specific application. When your app has a settings activity
177that allows users to control network usage, you should declare this intent filter for that activity.
178In the sample application, this action is handled by the class
179<code>SettingsActivity</code>, which displays a preferences UI to let users
180decide when to download a feed.</li>
181
182</ul>
183
184
185<pre>
186&lt;?xml version="1.0" encoding="utf-8"?&gt;
187&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
188    package="com.example.android.networkusage"
189    ...&gt;
190
191    &lt;uses-sdk android:minSdkVersion="4"
192           android:targetSdkVersion="14" /&gt;
193
194    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
195    &lt;uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&gt;
196
197    &lt;application
198        ...&gt;
199        ...
200        &lt;activity android:label="SettingsActivity" android:name=".SettingsActivity"&gt;
201             &lt;intent-filter&gt;
202                &lt;action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /&gt;
203                &lt;category android:name="android.intent.category.DEFAULT" /&gt;
204          &lt;/intent-filter&gt;
205        &lt;/activity&gt;
206    &lt;/application&gt;
207&lt;/manifest&gt;
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
214android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} action.
215<code>SettingsActivity</code> is a subclass of {@link
216android.preference.PreferenceActivity}. It displays a preferences screen
217(shown in figure 1) that
218lets 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
223each entry.</li>
224
225  <li>Whether to download the XML feed if any network connection is available,
226or 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}.
237When a user changes a preference, it fires
238{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged onSharedPreferenceChanged()},
239which sets {@code refreshDisplay} to true. This causes the display to refresh when the user
240returns to the main activity:</p>
241
242<pre>public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
243
244    &#64;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    &#64;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    &#64;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 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    &#64;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
287consequences for the app's behavior. In this snippet, the app checks the
288preferences settings in {@code onStart()}. if there is a match between the setting and
289the device's network connection (for example, if the setting is {@code "Wi-Fi"} and the
290device has a Wi-Fi connection), the app downloads the feed and refreshes the
291display.</p>
292
293<pre>
294public 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    &#64;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    &#64;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    &#64;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
385android.content.BroadcastReceiver} subclass, <code>NetworkReceiver</code>. When
386the device's network connection changes, <code>NetworkReceiver</code> intercepts
387the  action {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION},
388determines what the  network connection status is, and sets the flags
389<code>wifiConnected</code> and <code>mobileConnected</code> to true/false
390accordingly. The upshot is that the next time the user returns to the app, the
391app 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
395drain on system resources.
396The sample application registers the
397{@link android.content.BroadcastReceiver} {@code NetworkReceiver} in
398{@link android.app.Activity#onCreate(android.os.Bundle) onCreate()},
399and it unregisters it in
400{@link android.app.Activity#onDestroy onDestroy()}. This is more lightweight
401than 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,
403even 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
405be woken up after the user leaves the app.
406If you do declare a {@code <receiver>} in the manifest and you know exactly
407where you need it, you can use
408{@link android.content.pm.PackageManager#setComponentEnabledSetting setComponentEnabledSetting()}
409to 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&#64;Override
416public 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