Applications written with networking components are far more dynamic and content-rich than those that are not. Applications leverage the network for a variety of reasons: to deliver fresh and updated content, to enable social networking features of an otherwise standalone application, to offload heavy processing to high-powered servers, and to allow for data storage beyond what the user can achieve on the device.
Deciding how much networking support your application should contain is part of the application design process—something we talk more about in Chapter 18, “The Mobile Software Development Process.”
Those accustomed to Java networking will find the java.net
package familiar. There are also some helpful Android utility classes for various types of network operations and protocols. This chapter focuses on Hypertext Transfer Protocol (HTTP), the most common protocol for networked mobile applications.
The most common way to transfer data to and from the network is to use HTTP. You can use HTTP to encapsulate almost any type of data and to secure the data with Secure Sockets Layer (SSL), which can be important when you transmit data that falls under privacy requirements. Also, most common ports used by HTTP are typically open from the phone networks.
Recall that as part of the Android Software Development Kit (SDK) License Agreement, developers agree to a number of best practices when it comes to network applications. If you plan to use network support in your application, you might want to review these points within the contract to ensure that your application complies with the agreement.
Reading data from the Web can be extremely simple. For example, if all you need to do is read some data from a Web site and you have the web address of that data, you can leverage the URL
class (available as part of the java.net
package) to read a fixed amount of text from a file on a web server, like this:
First, a new URL
object is created with the URL to the data we want to read. A stream is then opened to the URL resource. From there, we read the data and close the InputStream
. Reading data from a server can be that simple.
However, remember that because we work with a network resource, errors can be more common. Our phone might not have network coverage; the server might be down for maintenance or disappear entirely; the URL might be invalid; and network users might experience long waits and timeouts.
This method might work in some instances, for example if your application has lightweight, noncritical network features, but it’s not particularly elegant. In many cases, you might want to know more about the data before reading from it from the URL. For instance, you might want to know how big it is.
Finally, for networking to work in any Android application, permission is required. Your application needs to have the following statement in its AndroidManifest.xml
file:
<uses-permission
android:name="android.permission.INTERNET"/>
We can use the HttpURLConnection
object to do a little reconnaissance on our URL before we transfer too much data. HttpURLConnection
retrieves some information about the resource referenced by the URL object, including HTTP status and header information.
Some of the information you can retrieve from the HttpURLConnection
includes the length of the content, content type, and date-time information so that you can check to see if the data changed since the last time you accessed the URL.
Here is a short example of how to use HttpURLConnection
to query the same URL previously used:
The log lines demonstrate a few useful methods with the HttpURLConnection
class. If the URL content is deemed appropriate, you can then call http.getInputStream()
to get the same InputStream
object as before. From there, reading from the network resource is the same, but more will be known about the resource.
Android ships with Apache Foundation’s HTTPClient v4 (http://hc.apache.org/), which has substantial changes from previous versions. You can find more information about protocol interaction within the org.apache.http
package.
A large portion of data transmitted between network resources is stored in a structured fashion in Extensible Markup Language (XML). In particular, RSS feeds are provided in a standardized XML format and many web services provide data using these feeds.
Android SDK provides a variety of XML utilities. We dabbled with the XML Pull Parser in Chapter 5, “Managing Application Resources.” We also covered the various SAX and DOM support available in Chapter 9, “Using Android Data and Storage APIs.”
Parsing XML from the network is similar to parsing an XML resource file or a raw file on the file system. Android provides a fast and efficient XML Pull Parser, which is a parser of choice for networked applications.
The following code demonstrates how to use the XML Pull Parser to read an XML file from flickr.com and extract specific data from within it. A TextView
called status
is assigned before this block of code is executed and displays the status of the parsing operation.
After the URL is created, the next step is to retrieve an XmlPullParser
instance from the XmlPullParserFactory
. A Pull Parser has a main method that returns the next event. The events returned by a Pull Parser are similar to methods used in the implementation of a SAX parser handler class. Instead, though, the code is handled iteratively. This method is more efficient for mobile use.
In this example, the only event that we check for is the START_TAG
event, signifying the beginning of an XML tag. Attribute values are queried and compared. This example looks specifically for image URLs within the XML from a flickr feed query. When found, a log entry is made.
You can check for the following XML Pull Parser events:
• START_TAG:
Returned when a new tag is found (that is, <tag>
)
• TEXT:
Returned when text is found (that is, <tag>text</tag>
where text has been found)
• END_TAG:
Returned when the end of tag is found (that is, </tag>
)
• END_DOCUMENT:
Returned when the end of the XML file has been reached
Additionally, the parser can be set to validate the input. Typically, parsing without validation is used when under constrained memory environments, such as a mobile environment. Compliant, nonvalidating parsing is the default for this XML Pull Parser.
The style of networking presented so far causes the UI thread it runs on to block until the operation finishes. For small tasks, this might be acceptable. However, when timeouts or additional processing is added, such as parsing XML, you want to move these time-intensive operations away from the main UI thread by launching a worker new thread. This provides a smoother experience for the user.
The following code demonstrates how to launch a new thread that connects to a remote server, retrieves and parses some XML, and posts a response back to the UI thread to change a TextView
:
For this example, an anonymous Thread
object will do. We create it and call its start()
method immediately. However, now that code runs on a separate thread, the user interface updates must be posted back to the main thread. This is done by using a Handler
object on the main thread and creating Runnable
objects that execute to call setText()
on the TextView
widget named status
.
The rest of the code remains the same as in the previous examples. Executing both the parsing code and the networking code on a separate thread allows the user interface to continue to behave in a responsive fashion while the network and parsing operations are done behind the scenes, resulting in a smooth and friendly user experience. This also allows for handling of interim actions by the user, such as canceling the transfer. You can accomplish this by implementing the Thread
to listen for certain events and check for certain flags.
Now that we covered how you can use a separate thread to parse XML, let’s take our example a bit deeper and talk about working with nonprimitive data types.
Continuing with the previous example of parsing for image locations from a flickr feed, let’s display some images from the feed. The following example reads the image data and displays it on the screen, demonstrating another way that network resources can be used:
You can find this block of code within the parser thread, as previously described. After the image source and title of the image have been determined, a new Runnable
object is queued for execution on a separate image handling thread. The thread is merely a queue that receives the anonymous Runnable
object created here and executes it at least 10 seconds after the last one, resulting in a slideshow of the images from the feed.
Although the preceding code is sound for local resources and URLs, for sources over slow connections, it might not work properly. This is a known issue with the Android SDK caused by a buffering issue with loading large bitmaps over slow connections. There is a relatively straightforward workaround that is found in the code provided for this chapter.
As with the first networking example, a new URL
object is created and an InputStream
retrieved from it. A Drawable
object is needed to assign to the ImageSwitcher
. Then we use the BitmapFactory.decodeStream()
method, which takes an InputStream
.
Finally, from this Runnable
object, which runs on a separate queuing thread, spacing out image drawing, another anonymous Runnable
object posts back to the main thread to actually update the ImageSwitcher
with the new image. Figure 10.1 shows what the screen might look like showing decoding status and displaying the current image.
Although all this continues to happen while the feed from flickr.com is decoded, certain operations are slower than others. For instance, while the image is decoded or drawn on the screen, a distinct hesitation is noticeable in the progress of the decoding. This is to be expected on current mobile devices because most have only a single thread of execution available for applications. Careful design is needed to provide a reasonably smooth and responsive experience to the user.
The Android SDK provides utilities for gathering information about the current state of the network. This is useful to determine if a network connection is even available before trying to use a network resource. The ConnectivityManager
class provides a number of methods to do this. The following code determines if the mobile (cellular) network is available and connected. In addition, it determines the same for the WiFi network:
First, an instance of the ConnectivityManager
object is retrieved with a call to the getSystemService()
method, available as part of your application Context
. Then this instance retrieves NetworkInfo
objects for both TYPE_WIFI
and TYPE_MOBILE
(for the cellular network). These objects are queried for their availability but can also be queried at a more detailed status level to learn exactly what state of connection (or disconnection) the network is in. Figure 10.2 shows the typical output for the emulator in which the mobile network is simulated but WiFi isn’t available.
If the network is available, that does not necessarily mean the server that the network resource is on is available. However, a call to the ConnectivityManager
method requestRouteToHost()
can answer this question. This way, the application can give the user better feedback when there are network problems.
Use the emulator networking settings to simulate various types of cellular networks, from GSM to HSDPA data rates. Additionally, you can control the latency of the network to be similar to that of the cellular networks. Although this is useful for testing how your application behaves in good conditions for the chosen network type, it can’t simulate the real behavior of the network out in the field when the user is in bad coverage, goes on an elevator, or is on a train rapidly losing and reacquiring network coverage. Only physical handset testing can truly reveal these results.
For your application to read the status of the network, it needs explicit permission. The following statement is required to be in its AndroidManifest.xml
file:
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"/>
Applications that get data from the Web often end up displaying that data on the screen. Instead of customizing various screens with widgets, an application can just use the WebView
widget, which uses the WebKit
rendering engine, to draw HTML data on the screen. This data can be HTML pages on the Web, as with our example, or it can be locally sourced.
Here is an example of how to use a WebView
widget to draw HTML.
The corresponding layout file section for this follows:
You do not need additional code to load the referenced web page on the screen. The call to the setInitialScale()
method scales the view to 30 percent of the original size. For pages that specify absolute sizes, scaling the view is necessary to see the entire page on the screen. Some text might become too small to read though, so testing and page design changes, if under your control, might be required for a good user experience.
The WebView
widget allows the user to navigate within the page and click on links. Clicking on links, by default, loads the default web browser on the system. Two classes, in particular, can help modify the behavior of the viewer and gather useful information from it. One of them is the WebViewClient
class, which allows the application to listen for certain WebView
status events, such as when a page is loading, when a form is submitted, and when a new URL is about to be loaded. The following is an example of how to handle the onPageFinished()
method to draw the title of the page on the screen:
When the page finishes loading, as indicated by the call to onPageFinished()
, a call to the getTitle()
method of the WebView
allows the title to be retrieved for use. The result of this call is shown in Figure 10.3.
Second, you can use the WebChromeClient
class in a similar way to the WebViewClient
. However, WebChromeClient
is specialized for the sorts of items that will be drawn outside the region in which the web content is drawn, typically known as browser chrome. It also includes some callbacks for certain JavaScript calls, such as onJsBeforeUnload()
, to confirm navigation away from a page.
The following code demonstrates interactivity from the user. An EditText
and Button
widget are added below the WebView
and the Button
handler is implemented as follows:
Calling the loadUrl()
method again, as shown, is all that is needed to cause the WebView
widget to download another HTML page for display, as shown in Figure 10.4. From here, a generic web browser can be built in to any application, but often restrictions will be applied so that the user is restricted to browsing relevant HTML documents (such as the application’s home server).
Whether you use WebView
to display the main user interface of your application or use it sparingly to draw such things as help pages, there are circumstances where it might be the ideal widget for the job to save coding time, especially when compared to a custom screen design. Leveraging the power of the open source engine, WebKit
, WebView
can provide a powerful, standards-based HTML viewer for applications. Support for WebKit
is widespread because it is used in various desktop browsers, including Safari and Google Chrome, and a variety of mobile browsers, including those on the Apple iPhone and Nokia S60.
Networking on the Android platform is standardized, using a combination of powerful yet familiar technologies and libraries such as java.net
and WebKit
. Although the implementation of networking features within applications is generally straightforward, mobile application developers need to plan for less stable connectivity than one might expect in a home or office network setting—connectivity depends on the location of the users and their device.
Integrating networking features into your mobile application needs to be considered at the design level. Users demand responsive applications, so time-intensive operations should not block from the main UI thread. Finally, don’t forget to handle application lifecycle events smoothly with network activities.
Java.net package information: http://developer.android.com/reference/java/net/package-summary.html
Android.net package information: http://developer.android.com/reference/android/net/package-summary.html
Android XML Pull Parser: http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html
More information on XML Pull Parsing: www.xmlpull.org/
WebKit Open Source Project: http://webkit.org/
3.149.243.130