Accessing the Internet (HTTP) Android

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.

Reading Data from the Web

Reading data from the Web can be extremely simple. For example, if all you need to do is read some data from a website 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:

import java.io.InputStream;
import java.net.URL;
// ... URL text = new URL(
“http://api.flickr.com/services/feeds/photos_public.gne” +
[email protected]&lang=en-us&format=atom”);
InputStream isText = text.openStream();
byte[] bText = new byte[250];
int readSize = isText.read(bText);
Log.i(“Net”, “readSize = “ + readSize);
Log.i(“Net”, “bText = “+ new String(bText));
isText.close();

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, when 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”/>

Using HttpURLConnection

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:

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
// ...
URL text = new URL(
“http://api.flickr.com/services/feeds/photos_public.gne
[email protected]&lang=en-us&format=atom”);
HttpURLConnection http =
(HttpURLConnection)text.openConnection();
Log.i(“Net”, “length = “ + http.getContentLength());
Log.i(“Net”, “respCode = “ + http.getResponseCode());
Log.i(“Net”, “contentType = “+ http.getContentType());
Log.i(“Net”, “content = “+http.getContent());

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 is known about the resource.

Parsing XML from the Network

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 dabble with the XML Pull Parser in Chapter “Managing Application Resources.”We also cover the various SAX and DOM support available in Chapter 10,“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.

import java.net.URL;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
// ...
URL text = new URL(
“http://api.flickr.com/services/feeds/photos_public.gne
[email protected]&lang=en-us&format=atom”);
XmlPullParserFactory parserCreator =
XmlPullParserFactory.newInstance();
XmlPullParser parser = parserCreator.newPullParser();
parser.setInput(text.openStream(), null);
status.setText(“Parsing...”);
int parserEvent = parser.getEventType();
while (parserEvent != XmlPullParser.END_DOCUMENT) {
switch(parserEvent) {
case XmlPullParser.START_TAG:
String tag = parser.getName();
if (tag.compareTo(“link”) == 0) {
String relType =
parser.getAttributeValue(null, “rel”);
if (relType.compareTo(“enclosure”) == 0 ) {
String encType =
parser.getAttributeValue(null, “type”);
if (encType.startsWith(“image/”)) {
String imageSrc =
parser.getAttributeValue(null, “href”);
Log.i(“Net”,
“image source = “ + imageSrc);
}
}
}
break;
}
parserEvent = parser.next();
}
status.setText(“Done...”);

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 is 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.

Processing Asynchronously

Users demand responsive applications, so time-intensive operations such as networking should not block the main UI thread. 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, large amounts of data, or additional processing, such as parsing XML, is added into the mix, you should move these time-intensive operations off of the main UI thread.

Offloading intensive operations such as networking provides a smoother, more stable experience to the user. The Android SDK provides two easy ways to manage offload processing from the main UI thread: the AsyncTask class and the standard Java Thread class.

The AsyncTask class is a special class for Android development that encapsulates background processing and helps facilitate communication to the UI thread while managing the lifecycle of the background task within the context of the activity lifecycle. Developers can also construct their own threading solutions using the standard Java methods and classes—but they are then responsible for managing the entire thread lifecycle as well.

Working with AsyncTask

AsyncTask is an abstract helper class for managing background operations that eventually post back to the UI thread. It creates a simpler interface for asynchronous operations than manually creating a Java Thread class.

Instead of creating threads for background processing and using messages and message handlers for updating the UI, you can create a subclass of AsyncTask and implement the appropriate event methods. The onPreExecute() method runs on the UI thread before background processing begins. The doInBackground() method handles background processing, whereas publishProgress() informs the UI thread periodically about the background processing progress. When the background processing finishes, the onPostExecute() method runs on the UI thread to give a final update.

The following code demonstrates an example implementation of AsyncTask to perform the same functionality as the code for the Thread:

private class ImageLoader extends
AsyncTask<URL, String, String> {
@Override
protected String doInBackground(
URL... params) {
// just one param
try {
URL text = params[0];
// ... parsing code {
publishProgress(
“imgCount = “ + curImageCount);
// ... end parsing code }
}
catch (Exception e ) {
Log.e(“Net”,
“Failed in parsing XML”, e);
return “Finished with failure.”;
}
return “Done...”;
}
protected void onCancelled() {
Log.e(“Net”, “Async task Cancelled”);
}
protected void onPostExecute(String result) {
mStatus.setText(result);
}
protected void onPreExecute() {
mStatus.setText(“About to load URL”);
}
protected void onProgressUpdate(
String... values) {
// just one value, please
mStatus.setText(values[0]);
}}

When launched with the AsyncTask.execute() method, doInBackground() runs in a background thread while the other methods run on the UI thread. There is no need to manage a Handler or post a Runnable object to it. This simplifies coding and debugging.

Using Threads for Network Calls

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:

import java.net.URL;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
// ...
new Thread() {
public void run() {
try {
URL text = new URL(
“http://api.flickr.com/services/feeds/photos_public.gne?
[email protected]&lang=en-us&format=atom”);
XmlPullParserFactory parserCreator =
XmlPullParserFactory.newInstance();
XmlPullParser parser =
parserCreator.newPullParser();
parser.setInput(text.openStream(), null);
mHandler.post(new Runnable() {
public void run() {
status.setText(“Parsing...”);
}
});
int parserEvent = parser.getEventType();
while (parserEvent !=
XmlPullParser.END_DOCUMENT){
// Parsing code here ...
parserEvent = parser.next();
}
mHandler.post(new Runnable() {
public void run(){
status.setText(“Done...”);
}
});
} catch (Exception e){
Log.e(“Net”, “Error in network call”, e);
}
}
}.start();

For this example, an anonymous Thread object will do. We create it and call its start() method immediately. However, now that the 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 Accessing the Internet (HTTP) 295 accomplish this by implementing the Thread to listen for certain events and check for certain flags.

Displaying Images from a Network Resource

Now that we have covered how you can use a separate thread to parse XML, let’s take our example a bit deeper and talk about working with non-primitive 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 you can use network resources:

import java.io.InputStream;
import java.net.URL;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import android.os.Handler;
// ...
final String imageSrc =
parser.getAttributeValue(null,“href”);
final String currentTitle = new String(title);
imageThread.queueEvent(new Runnable(){
public void run(){
InputStream bmis;
try{
bmis = new URL(imageSrc).openStream();
final Drawable image = new BitmapDrawable(
BitmapFactory.decodeStream(bmis));
mHandler.post(new Runnable(){
public void run(){
imageSwitcher.setImageDrawable(image);
info.setText(currentTitle);
}
});
} catch (Exception e){
Log.e(“Net”, “Failed to grab image”, e);
}
}
});

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.

As with the first networking example, a new URL object is created and an InputStream retrieved from it. You need a Drawable object to assign to the ImageSwitcher. Then you 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 shows what the screen might look like showing decoding status and displaying the current image.

Screen showing a flickr image and decoding status of feed.

Screen showing a flickr image and decoding status of feed

Although all this continues to happen while the feed from flickr is decoded, certain operations are slower than others. For instance, while the image is decoded or drawn on the screen, you can notice a distinct hesitation 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. You need to use careful design to provide a reasonably smooth and responsive experience to the user.

Retrieving Android Network Status

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 Wi-Fi network:

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
// ...
ConnectivityManager cm = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni =
cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
boolean isWifiAvail = ni.isAvailable();
boolean isWifiConn = ni.isConnected();
ni = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isMobileAvail = ni.isAvailable();
boolean isMobileConn = ni.isConnected();
status.setText(“WiFinAvail = “+ isWifiAvail +
“nConn = “ + isWifiConn +
“nMobilenAvail = “+ isMobileAvail +
“nConn = “ + isMobileConn);

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 shows the typical output for the emulator in which the mobile network is simulated but Wi-Fi isn’t available.

If the network is available, this 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.

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”/>

Typical network status of the Android SDK emulator.

Typical network status of the Android SDK emulator.



Face Book Twitter Google Plus Instagram Youtube Linkedin Myspace Pinterest Soundcloud Wikipedia

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Android Topics