This article, which builds on the foundation described in “Develop Android applications with Android Studio,” explores the networking capabilities of Android. Learn how to leverage Android’s networking capabilities for fun and useful purposes. The Android platform is ideal for Java™ developers: They can use existing skills to bring network connectivity to a mobile, or “embedded,” platform.

In this article, learn some networking options available for Android applications and about basic Android networking skills. Explore a hypothetical application that requires networking when used with an environmental monitoring system. Why would such a system be important? Here’s one reason: A friend went out of town for a few weeks. While he was away, he called and asked me to pick something up at his house to mail it to him. When at his house, I realized the heat had shut off and the pipes had burst — not a pretty picture. If a temperature monitoring system had been in place, the damage could have been averted. This article examines the roles Android can play in such a monitoring system.

Android networking capabilities

Android is based on the Linux® kernel and contains a healthy array of networking capabilities. If you have not installed the Android Studio and configured it to build applications, you might want to take a moment to do so now in order to better follow along with the example.

Table 1 shows some networking-related packages in the Android SDK.

Package Description
java.net Provides networking-related classes,including stream and datagram sockets, Internet Protocol, and generic HTTP handling. This is the multipurpose networking resource. Experienced Java developers can create applications right away with this familiar package.
java.io Though not explicitly networking, it’s very important. Classes in this package are used by sockets and connections provided in other Java packages. They’re also used for interacting with local files (a frequent occurrence when interacting with the network).
java.nio Contains classes that represent buffers of specific data types. Handy for network communications between two Java language-based end points.
org.apache.* Represents a number of packages that provide fine control and functions for HTTP communications. You might recognize Apache as the popular open source Web server.
android.net Contains additional network access sockets beyond the core java.net.* classes. This package includes the URI class, which is used frequently in Android application development beyond traditional networking.
android.net.http Contains classes for manipulating SSL certificates.
android.net.wifi Contains classes for managing all aspects of WiFi (802.11 wireless Ethernet) on the Android platform. Not all devices are equipped with WiFi capability, particularly as Android makes headway in the “flip-phone” strata of cell phones from manufacturers like Motorola and LG.
android.telephony.gsm Contains classes required for managing and sending SMS (text) messages. Over time, an additional package will likely be introduced to provide similar functions on non-GSM networks, such as CDMA, or something like android.telephony.cdma.

The list above is not exhaustive, but it is meant to give you a high-level awareness of what the platform is capable of. The next section explores a few simple networking examples.

Simple networking example

To demonstrate just how easy it is to connect Android to a network, the example will show how to pull text from a Web page. Download the source code for the example. Figure 1 demonstrates the application in action.

Figure 1. Fetching text from a Web page

Fetching text from a Web page

This section provides the code necessary to build the example application. We’ll first look at the UI aspects, then cover networking-related code. There are three UI elements:

  • EditText lets the user enter a Web page (https://google.com is shown in Figure 1 and Listing 2).
  • A button is used to tell the program to fetch the Web page text.
  • Once the data is received, it is shown in a TextView.

Listing 1 shows the file main.xml, which is the complete UI layout for this application.

Listing 1. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
    >
<EditText
    android:layout_height="wrap_content"
    android:id="@+id/address"
    android:layout_width="match_parent"
    android:text="https://google.com"
    >
</EditText>
<Button
    android:id="@+id/ButtonGo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="go!"
    >
</Button>

    <TextView
        android:id="@+id/pagetext"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:scrollbars="vertical"
        android:textColor="#000000" />
</LinearLayout>

Listing 2 shows the Java code used by this example.

Listing 2. MainActivity.java

package com.navitend.getwebpage;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;


public class MainActivity extends Activity {
    EditText eText;
    TextView tView;
    Button button;
    String tag = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.i(tag,"onCreate");

        eText = (EditText) findViewById(R.id.address);
        tView = (TextView) findViewById(R.id.pagetext);
        tView.setMovementMethod(new ScrollingMovementMethod());     // allow textView to scroll

        button = (Button) findViewById(R.id.ButtonGo);

        button.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                String url = eText.getText().toString();
                new GetData(tView).execute(url);
            }
        });
    }       // onCreate

    private class GetData extends AsyncTask<String, Void, String> {
        private TextView textView;

        public GetData(TextView textView) {
            this.textView = textView;
        }

        @Override
        protected String doInBackground(String... strings) {
            String webpageData = null;
            try {
                URL url = new URL(strings[0]);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

                InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
                StringBuilder sb = new StringBuilder();

                String inputString;
                while ((inputString = bufferedReader.readLine()) != null) {
                    sb.append(inputString);
                }

                webpageData = sb.toString();
                urlConnection.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.i(tag,"Data retrieved from site:" + webpageData);
            return webpageData;
        }

        @Override
        protected void onPostExecute(String pageText) {
            textView.setText(pageText);
        }
    }   // GetData
} // MainActivity class

Before going into more detail around the code itself, it is important to understand two central rules every Android developer needs to abide by:

  • Never attempt a “long-running” task directly on the UI thread. Why not? We do not want a slow network activity such as downloading a large file from a web server to impair the experience of the user. No one enjoys an unresponsive application. This idea of a responsive user interface leads us to the second rule.

  • Only the main/UI thread of an application can interact with the user interface elements (in other words, changing the contents of a View). This means that all modifications to the user interface must be done from the main thread of the application.

If you can only fetch data on a “background” thread and you’re not permitted to update the user interface from anything other than the main thread, you’re in a bit of a jam. How do you satisfy both requirements?

There are a handful of design patterns available to comply with these two constraints. Some of these approaches are more straight-forward than others. It is easy to get caught in the weeds and idiosyncratic consequences of Threads and Handlers, static classes, inner classes and employing sub-classing and WeakReferences to side-step memory leaks. While some computer science majors and Java purists may enjoy the details of these approaches, we are going to leverage the class offered by Android to wrap all of this drama up into a simple design pattern – we employ the AsyncTask.

The AsyncTask class wraps up all of the threading and UI interactions in a manner that offers both a place to implement our networking code and a place to interact with the user interface. The MainActivity.java file shown in Figure 1 has two classes, our application’s Activity along with our implementation of AsyncTask.

The Activity code is pretty boring – we inflate the UI from activity_main.xml, obtain references to an EditText which permits entry of a url, a TextView to display retrieved page contents, and a Button to trigger the action.

The only item of interest in this class is the invocation of setMovementMethod on the TextView. This method causes the TextView to be scrollable vertically in order to see all of the retrieved data.

In the Button click handler, we instantiate an instance of the class GetData which extends AsyncTask.

In the GetData constructor, we pass in an element of the UI which we want to subsequently update – in this case our TextView.

The heavy lifting of an AsyncTask is performed in the doInBackground method. This is where the URL and HttpURLConnection classes team up to provide the actual connectivity to a Web site of the user’s choosing. An instance of a BufferedReader takes care of reading data coming in from the Web-site connection. As each line is read, the text is appended to a StringBuilder. Once doInBackground completes, the onPostExecute method receives the results of doInBackground and updates the user interface. Data on background thread? Check. Update UI on main thread? Check. Thank you, AsyncTask!

In this example, the Android application is communicating with an HTTP Web server, such as Apache or Internet Information Server (IIS on a Microsoft® server). While HTTP is an extremely popular protocol, there are other protocols in play on the Internet. If the application was talking directly to a TCP socket, instead of HTTP, you would implement the networking code slightly differently. Listing 3 is a code snippet showing another means of interacting with a remote server. The listing is implemented as a separate thread rather than within the doInBackground method of an AsyncTask implementation. In this example, the code is reading a single byte (or character) at a time. Once the complete response is read, the data is packaged up into a Message class instance and sent to an instance of a Handler. While the Handler is not shown in this listing, this shows an alternate means of obtaining data and sending it to another Thread. It is advised to stick with the AsyncTask approach unless a more pressing reason presents itself.

Listing 3. Daytime client

    public class Requester extends Thread {
        Socket requestSocket;
        String message;
        StringBuilder returnStringBuffer = new StringBuilder();
        Message lmsg;
        int ch;
        @Override
        public void run() {
            try {
                this.requestSocket = new Socket("remote.servername.com", 13);
                InputStreamReader isr = new InputStreamReader(this.requestSocket.
getInputStream(), "ISO-8859-1");
                while ((this.ch = isr.read()) != -1) {
                    this.returnStringBuffer.append((char) this.ch);
                }
                this.message = this.returnStringBuffer.toString();
                this.lmsg = new Message();
                this.lmsg.obj = this.message;
                this.lmsg.what = 0;
                h.sendMessage(this.lmsg);
                this.requestSocket.close();
            } catch (Exception ee) {
                Log.d("sample application", "failed to read data" + ee.getMessage());
            }
        }
    }

Unlike the code in Listing 1, this example is not communicating with an HTTP server, so you don’t employ the HttpURLConnection class. Instead, using the lower-level Socket class opens a stream-based socket connection to a remote server at port 13. Port 13 is the classic “Daytime Server” application.

The Daytime Server accepts an incoming socket connection and sends the date and time in a textual format back to the calling socket. Once the data has been sent, the socket is closed by the server. The example also demonstrates use of an InputStreamReader and a specific character encoding.

Sending a text message is another task you might want to do with Android. Listing 4 shows an example.

Listing 4. Send a text message

void sendMessage(String recipient,String myMessage) {
 SmsManager sm = SmsManager.getDefault();
 sm.sendTextMessage("destination number",null,"hello there",null,null);
}

Sending a text message is straightforward. First, obtain a reference to the SmsManager using the static method getDefault(). Then invoke the sendTextMessage method. The arguments:

  • Recipient cell-phone number: Include area code.
  • Service center phone number: Using null means that you are satisfied with using the default service center for processing the message. In all but the most novel of applications, use null for this parameter.
  • Your payload: Keep the message length fewer than 160 bytes, unless you are OK with the data being split up across multiple messages.
  • Pending intent: An optional intent to be started when the message is sent or an error occurs. It’s OK to pass a value of null for this parameter if this notification is not needed. (See Resources for more information about intents and Android fundamentals.)
  • Delivery intent: An optional Intent to be started when delivery confirmation is received. It’s OK to pass a value of null for this parameter if delivery notification is not important.

Whether connecting to a Web page or a custom TCP application, the Android platform is ready and able to assist. As shown in Listing 4, sending a text message is easy. By using the optional intent parameters, you can even take action once the message has been sent and then subsequently delivered. The next section takes a quick look at a potential application of networking with Android.

Survey of the environmental monitoring system

For this scenario, let’s assume you’re the property manager for several office condos where your business resides. Managing property is not much different from managing a data center — long stretches of boredom interrupted by acute opportunities for excitement. Just the other day, you had to oversee a clean-up operation after a 10-year-old water heater leaked all over a storage closet full of old PCs and training manuals. Fortunately, you were in town. If you had been traveling, the situation would have been really ugly. This mishap, and others like it, inspired the idea to explore using Android to assist in monitoring the condition of the property. Figure 2 is a high-level block diagram of such a system.

Figure 2. High-level block diagram of monitoring system

High-level block diagram of monitoring system

The architecture is a traditional approach using a microcontroller to interact with some simple sensors to collect data. Data is then sent to a controller with a serial communications protocol, such as RS232 or RS485. The controller would likely be a PC or similar machine. This data can then be accessed over the Internet through a firewall. The protocol used between the Android phone could be either HTTP or a proprietary scheme.

The data sent between the controller and the Android-equipped device would be basic bytes representing:

  • The presence of water
  • The current temperature
  • How much power is being consumed
  • Perhaps some general-purpose analog and digital values

Why would you care about power consumed? One reason might simply be that someone left the lights on and it’s raising the electric bill. A second reason could be a bit more problematic: Let’s say you have a large freezer and the power has gone out. That could be a messy and costly situation to cope with. Or, perhaps the circuit breaker on your air conditioning unit has tripped and your computer room is no longer cooling.

The basic design looks workable. In terms of using Android, you could replace Android in Figure 2 with just about any mobile platform. But what if you replace the microcontroller with an Android-equipped appliance? The next section discusses extending the application and what features are enabled by bringing Android more prominently into the picture.

Extending the application

The first architecture in this article centered around a microcontroller. Microcontrollers come in all shapes and sizes, from 6 pin “10F” parts from Microchip up to 32-bit monsters with loads of peripherals, pins, and code space. What if you put Android into the appliance instead of a traditional microcontroller? For some applications, this might be a nonstarter due to cost, but entertain the possibilities of this approach as you contemplate Figure 3.

Figure 3. Possible architecture of Android in an appliance

Possible architecture of Android in an appliance

Deploying Android to the embedded side of the picture lets you work with a richer programming environment. You can continue to monitor the same moisture, temperature, and power-consumption characteristics, but now you could also look at recording audio, video, and vibration. You could have a mini-alarm, access-control system, and an environmental monitoring tool. Because Android is so network-ready, you can do without the controller personal computer and talk directly to the network. This approach also provides additional benefits for updating the software in the field. Assume you want to add a new feature to the monitoring software (or even fix a bug). With the traditional microcontroller approach, that task can be cumbersome at best and downright expensive or impossible at worst. With Android, you have a cleaner deployment model with much more flexibility. Android is running primarily on mobile phones today, but it has been ported to NetBooks and other platforms. Hopefully this article has given you some food for thought. I’ve got to go and get my system running. You never know when another water heater is going to leak.

Summary

In this article, you learned about Android networking in general. You walked through a few samples of applications you could create, including interacting with a Web server and sending a text message. You saw how Android could be connected to a real-world environmental monitoring system. With code examples, you learned about opportunities for extending Android into some atypical applications, such as an embedded controller.