Let’s Talk: Efficient Communication for PHP and Android, Part 1

This entry is part 1 of 2 in the series Let's Talk: Efficient Communication for PHP and Android

Let's Talk: Efficient Communication for PHP and Android

The mobile space has exploded in the last several years, prompting the realization that service-oriented architecture is a great way to implement business logic for consumption by both web and mobile applications. While mobile devices have evolved dramatically, their increased availability to consumers has added strain on networks and service providers who are still struggling to make capacity meet demand. To keep hardware costs down, developers must now pinch bytes of bandwidth just as they did with memory back in the early days of computing.

This two-part article will guide you through the process of building an efficient PHP-based REST web service to be consumed by an Android-based application. Some of the concepts presented here are also applicable to other mobile platforms, such as iOS. I assume you already know the basics of PHP and Android development and that you have a suitable development environments set up for both. I’ll focus mainly on showing you how to handle data serialization and compression in both environments.

A Common Request

Here are the particular parts of a typical HTTP operation that we’re interested in:

  1. The client (e.g. the Android application) sends an HTTP request to the REST service (e.g. the server) and uses request headers to indicate which data serialization and compression formats it supports.
  2. Based on the request headers, the server determines which data serialization and compression formats it has in common with the client, selects one of each, applies them to the requested data, and sends a response containing headers specifying its selections and the data back to the client.
  3. Based on the response headers, the client applies the corresponding decompression and deserialization routines to the data to restore it to its original state and can then use it for its intended purpose.

Let’s start at the beginning and go through each step.

Requesting Data

In order to make HTTP requests, your Android application needs permission to access the Internet. You need to declare this in your project’s AndroidManifest.xml file like so:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
 <uses-permission android:name="android.permission.INTERNET" />
</manifest>

Afterwards, you need a class that actually handles making the HTTP requests and processing the responses. For this I will use the native AndroidHttpClient class which comes with a default configuration suitable for most purposes including use of a thread-safe connection manager.

The AndroidHttpClient class is only available in Android 2.2 (API level 8) and above. To support older versions, look at the DefaultHttpClient class from the Apache Harmony library that Android has included since its first version.

import android.net.http.AndroidHttpClient;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;

public class DataModel {
    protected AndroidHttpClient httpClient;
    protected HttpGet httpRequest;

    public DataModel() {
        this.httpClient = AndroidHttpClient.newInstance(
            "Android " + android.os.Build.VERSION.RELEASE
            // Your app name would also be an acceptable value here
        );
    }

    public DataValueObject getData() throws IOException {
        HttpGet httpRequest = new HttpGet(
            "http://10.0.2.2/php-android/");
        httpRequest.addHeader("Accept", 
            "application/json;q=1,application/x-msgpack;q=0.9");
        httpRequest.addHeader("Accept-Encoding", 
            "bzip2,gzip,deflate");
        HttpResponse httpResponse = this.httpClient.execute(httpRequest);
        // ...
    }
}

When this class is instantiated, it internally creates an instance of AndroidHttpClient. When the getData() method is called to request data, it creates an instance of HttpGet, populates it with request data, and uses the AndroidHttpClient instance to send it. Included in the request data are the following:

  1. The URL of the resource being requested (i.e. your REST endpoint). If you host this on the same machine hosting your Android development environment, you can access it from the emulator using the IP address 10.0.2.2 (as in the above example) and from a physical device plugged in via USB using the IP address 10.0.1.2.
  2. The data serialization formats supported by the client, in this case JSON and MessagePack, and their respective quality factors, floating point numbers between 0 and 1 with higher numbers indicating a higher preference for that particular format. More information on these can be found in RFC 2616 Section 12.
  3. The data encoding formats supported by the client, in this case bzip2, gzip, and deflate. More information on these can be found in RFC 2616 Section 3.5.
  4. It’s possible for the AndroidHttpClient instance to encounter issues, such as the server not being available. Its execute() method can throw an IOException to indicate this, which the code calling getData() can catch and handle as appropriate.

    We’ll come back to the rest of the getData() method in a later section when we examine processing the response, but for now we need to implement use of this class in an Android activity.

    Implementing a Background Task

    Requesting and processing data in the context of a mobile application is an asynchronous operation. That is, we want the application to send the request for the data and then take some action once the response is received, such as populating the user interface with the data.

    By default, Android contains each individual app in its own process and thread, the latter of which is often called the UI thread because user interface operations run on it. As such, intensive operations like obtaining and processing data from a web service should be run on a separate thread so as not to block UI operations, which generally results in irritated users. To do this, we need to write a subclass of AsyncTask to encapsulate the process.

    import java.io.IOException;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.app.ProgressDialog;
    import android.content.DialogInterface;
    import android.os.AsyncTask;
    
    public class GetDataTask extends AsyncTask<Void, Void, DataValueObject> {
        ProgressDialog progressDialog;
        Activity activity;
        String error;
        
        public GetDataTask(Activity activity) {
            super();
            this.activity = activity;
        }
        
        protected String getString(int id) {
            return this.activity.getResources().getString(id);
        }
        
        @Override
        protected void onPreExecute() {
            progressDialog = ProgressDialog.show(
                this.activity,
                "", 
                getString(R.string.loading),
                true,
                false
            );
        }
    
        @Override
        protected DataValueObject doInBackground(Void... params) {
            DataModel dataModel = new DataModel();
            DataValueObject dvo = null;
            try {
                dvo = dataModel.getData();
            } catch (IOException e) {
                this.error = getString(R.string.error); // or e.getMessage() when debugging
            }
            return dvo;
        }
        
        @Override
        protected void onPostExecute(DataValueObject dvo) {
            if (dvo != null) {
                // Do something useful with dvo here
                
                // Dismiss the progress dialog when done
                progressDialog.dismiss();
            } else {
                // Dismiss the progress dialog
                progressDialog.dismiss();
                
                // Display a simple error dialog to the user
                new AlertDialog.Builder(this.activity)
                    .setMessage(this.error)
                    .setNeutralButton(
                        getString(R.string.ok),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        }
                    )
                    .create()
                    .show();
            }
        }
    }

    As part of extending AsyncTask, this class specifies that the result of the operation will be an instance of the DataValueObject class which the getData() method of the DataModel class returns. The class constructor takes as its only parameter the activity instance that’s invoking it. This is used later to access localized strings and use the activity in other context-specific tasks.

    The onPreExecute() and onPostExecute() methods will vary depending on what you want to do before and after the background operation starts. My examples above show a simple use case of displaying a progress dialog and potentially an alert dialog when an error occurs.

    doInBackground() contains the logic that needs to run in a background thread, in this case calling getData(). It returns an instance of DataValueObject or null if an error occurs. That value is then passed to onPostExecute() when it’s invoked so you can do something useful with it.

    Executing the Background Task

    Now that we’ve properly encapsulated the background task we want to run to fetch the data, we need to actually invoke it in an activity. Part of this will require checking that a network connection is available so that the request for data can actually get to the server. Doing this requires adding an additional permission to your AndroidManifest.xml file:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest ...>
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    </manifest>

    An activity class that kicks off the background task when the activity is created might look like this:

    import android.app.Activity;
    import android.content.Context;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    import android.os.Bundle;
    
    public class MyActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (networkIsAvailable()) {
                new GetDataTask(this).execute();
            } else {
                // Display an error to the user about network unavailability
            }
        }
    
        public boolean networkIsAvailable() {
            ConnectivityManager cm = (ConnectivityManager) 
                getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = cm.getActiveNetworkInfo();
            return networkInfo != null && networkInfo.isConnected();
        }
    }

    The networkIsAvailable() method simply queries the appropriate service to determine if a network connection is available. If your application has a base activity class, this may be a useful method to include in it. The onCreate() activity hook uses networkIsAvailable() to either execute the background task or display an appropriate error message to the user. Executing the task is simply a matter of instantiating it with a reference to the activity and calling its execute() method.

    Next Time

    Part 1 of this article has focused mainly on setting up the Android application to make the request. In part 2 of this article coming up, we’ll get into the meat of handling data serialization and compression in both environments. Stay tuned!

    Image via Fotolia

Let's Talk: Efficient Communication for PHP and Android

Let’s Talk: Efficient Communication for PHP and Android, Part 2 >>

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://x Adam

    Hey Matt,
    great article, but most RESTfull applications that I encounter need to access the server through HTTPS. Can you point me in the correct direction towards writing a successful HTTPS client in Android (ie. suggest articles or books that would help)
    Thanks.

  • http://matthewturland.com Matthew Turland

    @Adam You should be able to adapt this example for DefaultHttpClient to use AndroidHttpClient instead: http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java

  • http://www.phpdevelopmentoutsourcing.com/ Jack Robert

    Hey Matt,
    Thanks for giving great and informative article. It is very helpful article. Thanks again

  • NssY

    This was very informative. I enjoyed it

  • novice question

    Hi Matt,
    Where is the DataValueObject class definition or am i missing something here?

  • http://matthewturland.com Matthew Turland

    Sorry if that wasn’t clear. DataValueObject was intended to represent a class that you define yourself to contain the data you’re using in your specific application. The class name was intended to be generic and can be named anything you like.