NETWORKING

The previous sections covered how to connect to the outside world using SMS and e-mail. Another way to achieve that is to use the HTTP protocol. Using the HTTP protocol, you can perform a wide variety of tasks, such as downloading web pages from a web server, downloading binary data, and so on.

The following Try It Out creates an Android project so you can use the HTTP protocol to connect to the Web to download all sorts of data.

TRY IT OUT: Creating the Base Project for HTTP Connection

codefile Networking.zip available for download at Wrox.com

1. Using Eclipse, create a new Android 3.0 project and name it Networking.

2. Add the following statement in bold to the AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.learn2develop.Networking"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="8" />
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>

3. Import the following namespaces in the MainActivity.java file:

package net.learn2develop.Networking;
 
import android.app.Activity;
import android.os.Bundle;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import android.widget.Toast;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
 
public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

4. Define the OpenHttpConnection() method in the MainActivity.java file:

public class MainActivity extends Activity {
 
    private InputStream OpenHttpConnection(String urlString)
    throws IOException
    {
        InputStream in = null;
        int response = -1;
 
        URL url = new URL(urlString);
        URLConnection conn = url.openConnection();
 
        if (!(conn instanceof HttpURLConnection))
            throw new IOException("Not an HTTP connection");
        try{
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");
            httpConn.connect();
            response = httpConn.getResponseCode();
            if (response == HttpURLConnection.HTTP_OK) {
                in = httpConn.getInputStream();
            }
        }
        catch (Exception ex)
        {
            throw new IOException("Error connecting");
        }
        return in;
    }
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

How It Works

Because you are using the HTTP protocol to connect to the Web, your application needs the INTERNET permission; hence, the first thing you did is add the permission in the AndroidManifest.xml file.

You then defined the OpenHttpConnection() method, which takes a URL string and returns an InputStream object. Using an InputStream object, you can download the data by reading bytes from the stream object. In this method, you made use of the HttpURLConnection object to open an HTTP connection with a remote URL. You set all the various properties of the connection, such as the request method, and so on:

            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");

After you try to establish a connection with the server, you get the HTTP response code from it. If the connection is established (via the response code HTTP_OK), then you proceed to get an InputStream object from the connection:

            httpConn.connect();
            response = httpConn.getResponseCode();
            if (response == HttpURLConnection.HTTP_OK) {
                in = httpConn.getInputStream();
            }

Using the InputStream object, you can then start to download the data from the server.

Downloading Binary Data

One of the common tasks you need to perform is downloading binary data from the Web. For example, you may want to download an image from a server so that you can display it in your application. The following Try It Out shows how this is done.

TRY IT OUT: Downloading Binary Data

1. Using the same project created earlier, add the following statements in bold to the main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
<ImageView
    android:id="@+id/img"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" />
</LinearLayout>

2. Add the following statements in bold to the MainActivity.java file:

public class MainActivity extends Activity {
    ImageView img;
 
    private InputStream OpenHttpConnection(String urlString)
    throws IOException
    {
        //...
    }
 
    private Bitmap DownloadImage(String URL)
    {
        Bitmap bitmap = null;
        InputStream in = null;
        try {
            in = OpenHttpConnection(URL);
            bitmap = BitmapFactory.decodeStream(in);
            in.close();
        } catch (IOException e1) {
            Toast.makeText(this, e1.getLocalizedMessage(),
                Toast.LENGTH_LONG).show();
 
            e1.printStackTrace();
        }
        return bitmap;
    }
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        //---download an image---
        Bitmap bitmap =
            DownloadImage(
            "http://www.mayoff.com/5-01cablecarDCP01934.jpg");
        img = (ImageView) findViewById(R.id.img);
        img.setImageBitmap(bitmap);
    }
}

3. Press F11 to debug the application on the Android emulator. Figure 5-15 shows the image downloaded from the Web and then displayed in the ImageView.

How It Works

The DownloadImage() method takes the URL of the image to download and then opens the connection to the server using the OpenHttpConnection() method that you have defined earlier. Using the InputStream object returned by the connection, the decodeStream() method from the BitmapFactory class is used to download and decode the data into a Bitmap object. The DownloadImage() method returns a Bitmap object.

The image is then displayed using an ImageView view.

REFERRING TO LOCALHOST FROM YOUR EMULATOR

When working with the Android emulator, you may frequently need to access data hosted on the local web server using localhost. For example, your own Web services are likely to be hosted on your local computer during development, and you’ll want to test them on the same development machine you use to write your Android applications. In such cases, you should use the special IP address of 10.0.2.2 (not 127.0.0.1) to refer to the host computer’s loopback interface. From the Android emulator’s perspective, localhost (127.0.0.1) refers to its own loopback interface.

Downloading Text Files

Besides downloading binary data, you can also download plain-text files. For example, you might be writing an RSS Reader application and therefore need to download RSS XML feeds for processing. The following Try It Out shows how you can download a plain-text file in your application.

TRY IT OUT: Downloading Plain-Text Files

1. Using the same project created earlier, add the following statements in bold to the MainActivity.java file:

public class MainActivity extends Activity {
    ImageView img;
 
    private InputStream OpenHttpConnection(String urlString)
    throws IOException
    {
        //...
    }
 
    private Bitmap DownloadImage(String URL)
    {
        //...
    }
 
    private String DownloadText(String URL)
    {
        int BUFFER_SIZE = 2000;
        InputStream in = null;
        try {
            in = OpenHttpConnection(URL);
        } catch (IOException e1) {
            Toast.makeText(this, e1.getLocalizedMessage(),
                Toast.LENGTH_LONG).show();
 
            e1.printStackTrace();
            return "";
        }
 
        InputStreamReader isr = new InputStreamReader(in);
        int charRead;
        String str = "";
        char[] inputBuffer = new char[BUFFER_SIZE];
        try {
            while ((charRead = isr.read(inputBuffer))>0)
            {
                //---convert the chars to a String---
                String readString =
                    String.copyValueOf(inputBuffer, 0, charRead);
                str += readString;
                inputBuffer = new char[BUFFER_SIZE];
            }
            in.close();
        } catch (IOException e) {
            Toast.makeText(this, e.getLocalizedMessage(),
                Toast.LENGTH_LONG).show();
 
            e.printStackTrace();
            return "";
        }
        return str;
    }
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        //---download an image---
        Bitmap bitmap =
            DownloadImage(
            "http://www.streetcar.org/mim/cable/images/cable-01.jpg");
        img = (ImageView) findViewById(R.id.img);
        img.setImageBitmap(bitmap);
 
        //---download an RSS feed---
        String str = DownloadText(
            "http://www.appleinsider.com/appleinsider.rss");
        Toast.makeText(getBaseContext(), str,
                       Toast.LENGTH_SHORT).show();
    }
}

2. Press F11 to debug the application on the Android emulator. Figure 5-16 shows the RSS feed downloaded and displayed using the Toast class.

How It Works

The DownloadText() method takes an URL of the text file to download and then returns the string of the text file downloaded. It basically opens an HTTP connection to the server and then uses an InputStreamReader object to read each character from the stream and save it in a String object.

Accessing Web Services Using the GET Method

So far, you have learned how to download images and text from the Web. The previous section showed how to download an RSS feed from a server. Very often, you need to download XML files and parse the contents (a good example of this is consuming Web services). Therefore, in this section you learn how to connect to a Web service using the HTTP GET method. Once the Web service returns a result in XML, you will extract the relevant parts and display its content using the Toast class.

For this example, the web method you will be using is from http://services.aonaware.com/DictService/DictService.asmx?op=Define. This web method is from a Dictionary Web service that returns the definition of a given word.

The web method takes a request in the following format:

GET /DictService/DictService.asmx/Define?word=string HTTP/1.1
Host: services.aonaware.com
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

It returns a response in the following format:

<?xml version="1.0" encoding="utf-8"?>
<WordDefinition xmlns="http://services.aonaware.com/webservices/">
  <Word>string</Word>
  <Definitions>
    <Definition>
      <Word>string</Word>
      <Dictionary>
        <Id>string</Id>
        <Name>string</Name>
      </Dictionary>
      <WordDefinition>string</WordDefinition>
    </Definition>
    <Definition>
      <Word>string</Word>
      <Dictionary>
        <Id>string</Id>
        <Name>string</Name>
      </Dictionary>
      <WordDefinition>string</WordDefinition>
    </Definition>
  </Definitions>
</WordDefinition>

Hence, to obtain the definition of a word, you need to establish an HTTP connection to the web method and then parse the XML result that is returned. The following Try It Out shows you how.

TRY IT OUT: Consuming Web Services

1. Using the same project created earlier, add the following statements in bold to the MainActivity.java file:

public class MainActivity extends Activity {
    ImageView img;
 
    private InputStream OpenHttpConnection(String urlString)
    throws IOException
    {
        //...
    }
 
    private Bitmap DownloadImage(String URL)
    {
        //...
    }
 
    private String DownloadText(String URL)
    {
        //...
    }
 
    private void WordDefinition(String word) {
        InputStream in = null;
        try {
            in = OpenHttpConnection(
"http://services.aonaware.com/DictService/DictService.asmx/Define?word=" + word);
            Document doc = null;
            DocumentBuilderFactory dbf =
                DocumentBuilderFactory.newInstance();
            DocumentBuilder db;
            try {
                db = dbf.newDocumentBuilder();
                doc = db.parse(in);
            } catch (ParserConfigurationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            doc.getDocumentElement().normalize();
 
            //---retrieve all the <Definition> nodes---
            NodeList itemNodes =
                doc.getElementsByTagName("Definition");
 
            String strDefinition = "";
            for (int i = 0; i < definitionElements.getLength(); i++) {
                Node itemNode = definitionElements.item(i);
                if (itemNode.getNodeType() == Node.ELEMENT_NODE)
                {
                    //---convert the Node into an Element---
                    Element definitionElement = (Element) itemNode;
 
                    //---get all the <WordDefinition> elements under
                    // the <Definition> element---
                    NodeList wordDefinitionElements =
                        (definitionElement).getElementsByTagName(
                        "WordDefinition");
 
                    strDefinition = "";
                    for (int j = 0; j < wordDefinitionElements.getLength(); j++) {
                        //---convert a <WordDefinition> Node into an Element---
                        Element wordDefinitionElement =
                            (Element) wordDefinitionElements.item(j);
 
                        //---get all the child nodes under the
                        // <WordDefinition> element---
                        NodeList textNodes =
                            ((Node) wordDefinitionElement).getChildNodes();
 
                        strDefinition +=
                            ((Node) textNodes.item(0)).getNodeValue() + ". ";
                    }
 
                    //---display the title---
                    Toast.makeText(getBaseContext(),strDefinition,
                        Toast.LENGTH_SHORT).show();
                }
            }
        } catch (IOException e1) {
            Toast.makeText(this, e1.getLocalizedMessage(),
                Toast.LENGTH_LONG).show();
            e1.printStackTrace();
        }
    }
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        //---download an image---
        Bitmap bitmap =
            DownloadImage(
            "http://www.mayoff.com/5-01cablecarDCP01934.jpg");
        img = (ImageView) findViewById(R.id.img);
        img.setImageBitmap(bitmap);
 
        //---download an RSS feed---
        String str = DownloadText(
            "http://www.appleinsider.com/appleinsider.rss");
        Toast.makeText(getBaseContext(), str,
                       Toast.LENGTH_SHORT).show();
 
        //---access a Web service using GET---
        WordDefinition("Apple");
    }
}

2. Press F11 to debug the application on the Android emulator. Figure 5-17 shows the result of the Web service call being parsed and then displayed using the Toast class.

How It Works

The WordDefinition() method first opens an HTTP connection to the Web service, passing in the word that you are interested in:

            in = OpenHttpConnection(
"http://services.aonaware.com/DictService/DictService.asmx/Define?word=" + word);

It then uses the DocumentBuilderFactory and DocumentBuilder objects to obtain a Document (DOM) object from an XML file (which is the XML result returned by the Web service):

            Document doc = null;
            DocumentBuilderFactory dbf =
                DocumentBuilderFactory.newInstance();
            DocumentBuilder db;
            try {
                db = dbf.newDocumentBuilder();
                doc = db.parse(in);
            } catch (ParserConfigurationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            doc.getDocumentElement().normalize();

Once the Document object is obtained, you find all the elements with the <Definition> tag:

            //---retrieve all the <Definition> nodes---
            NodeList itemNodes =
                doc.getElementsByTagName("Definition");

Figure 5-18 shows the structure of the XML document returned by the Web service.

Because the definition of a word is contained within the <WordDefinition> element, you then proceed to extract all the definitions:

            String strDefinition = "";
            for (int i = 0; i < definitionElements.getLength(); i++) {
                Node itemNode = definitionElements.item(i);
                if (itemNode.getNodeType() == Node.ELEMENT_NODE)
                {
                    //---convert the Node into an Element---
                    Element definitionElement = (Element) itemNode;
 
                    //---get all the <WordDefinition> elements under
                    // the <Definition> element---
                    NodeList wordDefinitionElements =
                        (definitionElement).getElementsByTagName(
                        "WordDefinition");
 
                    strDefinition = "";
                    for (int j = 0; j < wordDefinitionElements.getLength(); j++) {
                        //---convert a <WordDefinition> Node into an Element---
                        Element wordDefinitionElement =
                            (Element) wordDefinitionElements.item(j);
 
                        //---get all the child nodes under the
                        // <WordDefinition> element---
                        NodeList textNodes =
                            ((Node) wordDefinitionElement).getChildNodes();
                        //---get the first node, which contains the text---
                        strDefinition +=
                            ((Node) textNodes.item(0)).getNodeValue() + ". ";
                    }
                    //---display the title---
                    Toast.makeText(getBaseContext(),strDefinition,
                        Toast.LENGTH_SHORT).show();
                }
            }
        } catch (IOException e1) {
            Toast.makeText(this, e1.getLocalizedMessage(),
                Toast.LENGTH_LONG).show();
            e1.printStackTrace();
        }

The preceding code loops through all the <Definition> elements looking for a child element named <WordDefinition>. The text content of the <WordDefinition> element contains the definition of a word. The Toast class displays each word definition that is retrieved.

Performing Asynchronous Calls

All the connections made in the previous few sections have been synchronous — that is, the connection to a server will not return until the data is received. In real life, this presents some problems due to network connections being inherently slow. When you connect to a server to download some data, the user interface of your application remains frozen until a response is obtained. In most cases, this is not acceptable. Hence, you need to ensure that the connection to the server is made in an asynchronous fashion.

The easiest way to connect to the server asynchronously is to use the AsyncTask class available in the Android SDK. Using AsyncTask enables you to perform background tasks in a separate thread and then return the result in a UI thread. That way, you can perform background operations without needing to handle complex threading issues.

Using the previous example of downloading an image from the server and then displaying the image in an ImageView, you could wrap the code in an instance of the AsyncTask class, as shown here:

public class MainActivity extends Activity {
    ImageView img;
 
    private class BackgroundTask extends AsyncTask
    <String, Void, Bitmap> {
        protected Bitmap doInBackground(String... url) {
             //---download an image---
            Bitmap bitmap = DownloadImage(url[0]);
            return bitmap;
        }
 
        protected void onPostExecute(Bitmap bitmap) {
            ImageView img = (ImageView) findViewById(R.id.img);
            img.setImageBitmap(bitmap);
        }
    }
 
    private InputStream OpenHttpConnection(String urlString)
    throws IOException
    {
        ...
    }

Basically, you defined a class that extends the AsyncTask class. In this case, there are two methods within the BackgroundTask class: doInBackground() and onPostExecute(). You put all the code that needs to be run asynchronously in the doInBackground() method. When the task is completed, the result is passed back via the onPostExecute() method. The onPostExecute() method is executed on the UI thread, hence it is thread safe to update the ImageView with the bitmap downloaded from the server.

To perform the asynchronous tasks, simply create an instance of the BackgroundTask class and call its execute() method:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
            new BackgroundTask().execute(
                ";http://www.mayoff.com/5-01cablecarDCP01934.jpg");
    }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset