Android: Using RestClient to communicate with Google App Engine

Post to Twitter

This is day four of my “five days of Android articles“. I recently stumbled upon RestClient which was created by Luke Lowrey. RestClient really makes calling web services very easy from Android as you can see from Luke’s article. Today I’m going to use RestClient to communicate to Google App Engine.


The first thing I’m going to do is construct the Android project. Once your Android project is created make sure to update the AndroidManifest.xml file to add the necessary permission since we are going to make HTTP calls:

<uses-permission android:name="android.permission.INTERNET" />

Create a Java class file called “RestClient” and grab Luke’s RestClient from here and paste the code in the new file. I also created a file called “RequestMethod.java” and placed the following code inside of it:

package com.giantflyingsaucer;

public enum RequestMethod
{
	GET,
	POST
}

For reference, here is the RestClient code from the RestClient.java file:

package com.giantflyingsaucer;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

// Code from: http://lukencode.com/2010/04/27/calling-web-services-in-android-using-httpclient/
public class RestClient
{
	private ArrayList<NameValuePair> params;
	private ArrayList<NameValuePair> headers;

	private String url;

	private int responseCode;
	private String message;

	private String response;

	public String getResponse()
	{
		return response;
	}

	public String getErrorMessage()
	{
		return message;
	}

	public int getResponseCode()
	{
		return responseCode;
	}

	public RestClient(String url) {
		this.url = url;
		params = new ArrayList<NameValuePair>();
		headers = new ArrayList<NameValuePair>();
	}

	public void AddParam(String name, String value)
	{
		params.add(new BasicNameValuePair(name, value));
	}

	public void AddHeader(String name, String value)
	{
		headers.add(new BasicNameValuePair(name, value));
	}

	public void Execute(RequestMethod method) throws Exception
	{
		switch (method)
		{
		case GET:
		{
			// add parameters
			String combinedParams = "";
			if (!params.isEmpty())
			{
				combinedParams += "?";
				for (NameValuePair p : params)
				{
					String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(),"UTF-8");
					if (combinedParams.length() > 1)
					{
						combinedParams += "&" + paramString;
					}
					else
					{
						combinedParams += paramString;
					}
				}
			}

			HttpGet request = new HttpGet(url + combinedParams);

			// add headers
			for (NameValuePair h : headers)
			{
				request.addHeader(h.getName(), h.getValue());
			}

			executeRequest(request, url);
			break;
		}
		case POST:
		{
			HttpPost request = new HttpPost(url);

			// add headers
			for (NameValuePair h : headers)
			{
				request.addHeader(h.getName(), h.getValue());
			}

			if (!params.isEmpty())
			{
				request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
			}

			executeRequest(request, url);
			break;
		}
		}
	}

	private void executeRequest(HttpUriRequest request, String url)
	{
		HttpClient client = new DefaultHttpClient();

		HttpResponse httpResponse;

		try
		{
			httpResponse = client.execute(request);
			responseCode = httpResponse.getStatusLine().getStatusCode();
			message = httpResponse.getStatusLine().getReasonPhrase();

			HttpEntity entity = httpResponse.getEntity();

			if (entity != null)
			{

				InputStream instream = entity.getContent();
				response = convertStreamToString(instream);

				// Closing the input stream will trigger connection release
				instream.close();
			}

		}
		catch (ClientProtocolException e)
		{
			client.getConnectionManager().shutdown();
			e.printStackTrace();
		}
		catch (IOException e)
		{
			client.getConnectionManager().shutdown();
			e.printStackTrace();
		}
	}

	private static String convertStreamToString(InputStream is)
	{

		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();

		String line = null;
		try
		{
			while ((line = reader.readLine()) != null)
			{
				sb.append(line + "\n");
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				is.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		return sb.toString();
	}
}

Going into the “main.xml” file I modified it to just have a TextView that is multiple lines and essentially can take up the entire screen if needed with the return data.

<?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"
    >
<TextView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:singleLine="false"
    android:id="@+id/outputTextView"
    />
</LinearLayout>

The actual activity file where the magic happens and utilizes the RestClient class looks like this:

package com.giantflyingsaucer;


import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;


public class AndroidHTTPClient extends Activity
{
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		TextView textView = (TextView)findViewById(R.id.outputTextView);

		RestClient client = new RestClient("http://10.0.2.2:8888/listenforrestclient");
		client.AddParam("message", "Hello World");

		try
		{
			client.Execute(RequestMethod.GET);
		}
		catch (Exception e)
		{
			textView.setText(e.getMessage());
		}

		String response = client.getResponse();
		textView.setText(response);
	}
}

A couple things to note:
1. You can see how dead simple RestClient is to use and how easy it is to add parameters.
2. I populate the multi line TextView with the result.

Before you run this project though we need to ensure there is a valid App Engine project to call so you need to now create a new Java App Engine project. Mine looks like this:

The “ListenForRestClientServlet.java” file that was generated is almost perfect for the simple example I’m doing but we do need to modify it just a touch to accept the parameter I’m going to pass in and expect to be echoed back to the Android client.

Here is the code for “ListenForRestClientServlet.java”:

package com.giantflyingsaucer;

import java.io.IOException;
import javax.servlet.http.*;

@SuppressWarnings("serial")
public class ListenForRestClientServlet extends HttpServlet
{
	public void doGet(HttpServletRequest req, HttpServletResponse resp)	throws IOException
	{
		String message = "NONE";

		resp.setContentType("text/plain");

		if (req.getParameterMap().containsKey("message"))
            message = req.getParameter("message");

		resp.getWriter().println("You said: " + message);
	}
}

Nothing difficult there at all if you’ve used Servlets or JSP in the past.

Before you fire up the Android client though make sure you are not using “localhost” or “127.0.0.1” since the emulator has it’s own loopback interface. See this issue for some details. Instead use either the actual IP address of the machine your App Engine project is hosted on or use “10.0.2.2” (like in the code above for the Android activity class).

Now we can finally test this all out. Fire up the App Engine project first (ensure the address is correct in the Android project). Now fire up the Android project next and see what happens. Hopefully you see something like this:

Although nothing visually stunning it does show you how to quickly build a service using App Engine that can talk to your Android device.

Post to Twitter

This entry was posted in Android, App Engine, Open Source. Bookmark the permalink.

8 Responses to Android: Using RestClient to communicate with Google App Engine

  1. Pingback: Five days of Android articles coming next week! « Giant Flying Saucer

  2. Pingback: Android: A bare bones way to access App Engine | Giant Flying Saucer

  3. Sergey says:

    in my case there is:

    RestClient client = new RestClient(“http://10.0.2.2/listenforrestclient”);

  4. liz says:

    thanks, this was a great example to get me headed in the right direction

  5. eli albert says:

    thanks – simple, succinct, and why would anybody want restlet?
    I’m about to try to use the post method involved above, hope it works.

  6. Faizan says:

    Thanks for this great tutorial.

    Can you please explain a little bit more about google app engine and it’s benefits? and why did you use google app engine?

    Thanks in advance.

  7. Abubakar Mehmood says:

    Thanks a million. Very well-explained. Brief yet comprehensive.

    May you prosper. Amen. :p

  8. umar says:

    Hello . Its great tutorial . Please help me out about a liitle problem that i have stated over here http://stackoverflow.com/questions/6051370/changing-text-view-into-list-view

    Tons of Thanks in advance

Comments are closed.