Home | History | Annotate | Download | only in network-ops
      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 = &quot;NetworkStatusExample&quot;;
     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 &quot;available.&quot; 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}&mdash;Allows applications to open network
    162 sockets.</li>
    163       
    164       <li>{@link android.Manifest.permission#ACCESS_NETWORK_STATE
    165 android.permission.ACCESS_NETWORK_STATE}&mdash;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 &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
    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     &#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
    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     &#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
    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 &lt;receiver&gt;} in the manifest. When you declare a 
    402 {@code &lt;receiver&gt;} 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 &lt;receiver&gt;} 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 &#64;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