Android Development: Implementing a simple Client-Server model

I’ve recently started playing around with the Android SDK and created some simple apps by using examples from the developer.android.com website. I’ve also been thinking about how to implement an application that needs to communicate with a database-driven back-end server. This would be useful for any app that needs to retrieve data from a central location.

Generally, in a large application, we’d want to use Web Services, and then make XML-RPC calls between the client and the server. This approach allows for extensibility and interoperability with a wide range of clients. However, it can be overkill for a simple application, where the client and server are tightly coupled.

A simple way to do this, without adding a significant amount of complexity, is to use a server-side script that accepts commands and arguments through the use of HTTP POST and returns data as a string. The client can then make calls to the server and pass data just like a web page form does.

In this example, I’ll show how to implement such a simple client/server model with a fairly straight-forward protocol. Note that sending data over HTTP is not secure, and that any sensitive information should be passed over HTTPS in a production environment. I’ve opted to use HTTP in this example for its simplicity and convenience.

This example assumes that the reader is familiar with:

  • The Java Programming Language
  • The Android SDK
  • Basic PHP Scripting
  • Setting up and running a PHP script on a web server

The simple app: Animals and their sounds

We’re going to use a simple app to demonstrate our client-server model. The app will basically retrieve a list of animals from the server and display it in a ListView. When the user selects an animal from the list, our app will then retrieve the sound that the animal makes from the server and display it as a Toast on the screen.

This will demonstrate how the client and the server can support multiple calls with a different set of parameters. The client will be an Android app (AndroidListClient) and the server will be a PHP script (AndroidListServer).

Here’s what the application will look like when we’re done:

When an animal is selected from the list, we'll display a toast with the sound the animal makes.

AndroidListServer — The PHP Script

Our server will just be a simple PHP script that supports two commands: getAnimalList and getAnimalSound.

getAnimalList

  • Parameters: None
  • Returns: A comma separated list of animals.

getAnimalSound

  • Parameters: animal – animal to get the sound for
  • Returns: String representation of the sound that the animal makes.

To determine which command the client is calling, we have a required parameter called command. Command can have two possible values: getAnimalList and getAnimalSound. The script should only process valid commands. For all invalid commands, the script will return an empty string.

Here’s what the code for our simple script will look like. You can also see it on Google Code: server.php

<?php
  // get the command
  $command = $_REQUEST['command'];

  // determine which command will be run
  if($command == "getAnimalList") {
    // return a list of animals
    echo "bird,dog,cat,cow,sheep";
  } else if($command == "getAnimalSound") {
    // get the animal parameter and send the right response
    $animal = $_REQUEST['animal'];
    if($animal == "bird") {
      echo "Chirp, Chirp";
    } else if($animal == "dog") {
      echo "Woof, Woof";
    } else if($animal == "cat") {
      echo "Meow, Meow";
    } else if($animal == "cow") {
      echo "Moo, Moo";
    } else if($animal == "sheep") {
      echo "Baa, Baa";
    } else {
      echo "I don't know.";
    }
  } else {
    echo "";
  }
?>

Note: You can see the script in action here: http://www.hassanpur.com/AndroidListServerExample/server.php (you’ll get a blank page, since we didn’t specify any parameters). Try adding a valid command parameter to the URL, like this: http://www.hassanpur.com/AndroidListServerExample/server.php?command=getAnimalList.

AndroidListClient — The Android app

Our Android app will consist of two classes: AndroidListClient (a ListActivity) and ServerInterface.

Let’s start by taking a look at the ServerInterface class, since this will be where we’ll do the communication with the server:

Class: ServerInterface – This class will provide our android app with some static methods to communicate with the server. The idea here is to abstract the details of the communication with the server. We’ll make an HTTP request to the server and send our parameters as POST data. We’ll then get the response and return it as a string. The executeHttpRequest method handles most of the work here. In addition, we implement some wrapper methods (getAnimalList, getAnimalSound) to construct the query string passed to the server.

As mentioned, most of the work is done by the executeHttpRequest method:

private static String executeHttpRequest(String data) {
	String result = "";
	try {
		URL url = new URL(SERVER_URL);
		URLConnection connection = url.openConnection();

		// We need to make sure we specify that we want to provide input and
		// get output from this connection. We also want to disable caching,
		// so that we get the most up-to-date result. And, we need to
		// specify the correct content type for our data.
		connection.setDoInput(true);
		connection.setDoOutput(true);
		connection.setUseCaches(false);
		connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

		// Send the POST data
		DataOutputStream dataOut = new DataOutputStream(connection.getOutputStream());
		dataOut.writeBytes(data);
		dataOut.flush();
		dataOut.close();

		// get the response from the server and store it in result
		DataInputStream dataIn = new DataInputStream(connection.getInputStream());
		String inputLine;
		while ((inputLine = dataIn.readLine()) != null) {
			result += inputLine;
		}
		dataIn.close();
	} catch (IOException e) {
		/*
		 * In case of an error, we're going to return a null String. This
		 * can be changed to a specific error message format if the client
		 * wants to do some error handling. For our simple app, we're just
		 * going to use the null to communicate a general error in
		 * retrieving the data.
		 */
		e.printStackTrace();
		result = null;
	}

	return result;
}

We then create a wrapper around this method for the getAnimalList and getAnimalSound commands. Here’s what the getAnimalList method looks like:

public static String getAnimalList() {
	/*
	 * Let's construct the query string. It should be a key/value pair. In
	 * this case, we just need to specify the command, so no additional
	 * arguments are needed.
	 */
	String data = "command=" + URLEncoder.encode("getAnimalList");
	return executeHttpRequest(data);
}

The getAnimalSound method is implemented the same way. Here’s a link to the full source code of the ServerInterface class.

Class: AndroidListClient – This is the entry point for our application. We will start with an empty ListView, and then launch a background thread to retrieve the list of animals from the server. We will then update the UI by populating the ListView with the animals. In addition, we’ll setup a listener so that if the user clicks on an animal, we’ll launch another thread in the background to retrieve the animal sound from the server, and then display it as a Toast.

Note: In this case we’re using an asynchronous method of retrieving the data from the server. This is because we don’t know exactly how long it will take to connect to the server, process the command, and get the result. In the meantime, we don’t want to block the main UI thread. For more info on this topic, take a look at this article on Painless threading.

In our AndroidListClass, we’ll have a private class named GetListTask (which extends AsyncTask). This will allow us to easily launch a thread in the background to handle the data retrieval and UI update. Our GetListTask class will override the doInBackground and onPostExecute methods. Here’s what the GetListTask class looks like:

	private class GetListTask extends AsyncTask {

		/**
		 * Let's make the http request and return the result as a String.
		 */
		protected String doInBackground(Object... args) {
			return ServerInterface.getAnimalList();
		}

		/**
		 * Parse the String result, and create a new array adapter for the list
		 * view.
		 */
		protected void onPostExecute(Object objResult) {
			// check to make sure we're dealing with a string
			if(objResult != null && objResult instanceof String) {
				String result = (String) objResult;
				// this is used to hold the string array, after tokenizing
				String[] responseList;

				// we'll use a string tokenizer, with "," (comma) as the delimiter
				StringTokenizer tk = new StringTokenizer(result, ",");

				// now we know how long the string array is
				responseList = new String[tk.countTokens()];

				// let's build the string array
				int i = 0;
				while(tk.hasMoreTokens()) {
					responseList[i++] = tk.nextToken();
				}

				// now we'll supply the data structure needed by this ListActivity
				ArrayAdapter<String> newAdapter = new ArrayAdapter<String>(mainActivity, R.layout.list, responseList);
				mainActivity.setListAdapter(newAdapter);
			}
		}

	}

We follow the same process for the GetAnimalSoundTask, but this time we’ll call the corresponding method ServerInterface.getAnimalSound(String animal).

Finally within the AndroidListClient.onCreate() method, we set up our item click listener and launch an instance of the GetListTask thread:

// Let's set up an item click listener to retrieve the animal sound and display it to the user as a Toast.
ListView lv = this.getListView();
lv.setOnItemClickListener(new OnItemClickListener() {

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		// Spawn a GetAnimalSoundTask thread. This thread will get the data from the server in the background, without blocking the main UI thread.
		(new GetAnimalSoundTask()).execute((Object)((TextView)view).getText());
	}

});

// Spawn a GetListTask thread. This thread will get the data from the server in the background, so as not to block our main (UI) thread.
(new GetListTask()).execute((Object)null);

And here’s the full source of the AndroidListClient class.

Note: When testing this code, make sure to give your app permission to access the INTERNET. I ran into this problem when I ran the code for the first time. This can be done by adding the following entry to your AndroidManifest.xml file:

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

The source code for both the AndroidListClient and AndroidListServer can be checked out from my Google Code repository: Android Examples. AndroidListClient can easily be imported into Eclipse, and AndroidListServer can be imported into Aptana.



This entry was posted in Android Development, Uncategorized and tagged , , , , . Bookmark the permalink.
  • http://www.perfecteddesigns.com Tom

    Hey I was wondering how I might edit this a bit. I have a website that I would like to offer the file downloads via a android app for my users as it would let them download right to the phone. How hard would it be to edit the php script to have a file name/description and contain a link to the file and then upon clicking the item to be downloaded in the app have it save it to the root of the sd card? I am new to this but this seems almost what I’m looking for please contact me by email if you reply to this

    • Omayma323

       please help me how to send php (server ) data in json to android client .can i use URL to send this data or what??

  • C

    Nice article, most of which, I don’t understand. But one question I do have is why did you use a bunch of else if statements instead of a switch in your first code block?

    • http://www.hassanpur.com/ mujtaba

      Thanks. Yes, a switch statement would have been better. I tend to program more in Java and C, where you can’t use switch statements for strings. :-)

  • ads

    hi,

    i’m trying to do the steps you mentioned here but i keep getting “Force Close” application error when i run it. I use Android 2.2 as my target and min level for API is 8. am i doing something wrong?

    • http://www.hassanpur.com/ mujtaba

      What kind of exception are you getting? Make sure to give your app permission to access the Internet by modifying the AndroidManifest.xml file.

  • b1lal

    how would this work in terms of sending images to server and retuning results from a php database of contacts. im working on a face recognition app for my final year project. i can save the people details as php database. and images in another database. so first you send sample image to server this is compared to the image database on the server and then retuns the contact details on the phone. i have figured out the recognition mechanism but not sure about how to communicate between client and server. any help would be appreciated.
    thankx

  • http://- yudo

    Hi ..
    I am a beginner
    I’ve followed your way
    but the result is empty :’(
    Can you share sample simple application it to my email, for the client and server

    thank you very much in advance :)

    • http://www.hassanpur.com/ mujtaba

      The source code for the client and server are available from my Google Code repository. Take a look at this post: Importing Hassanpur.com example projects into Eclipse and Aptana.

      • SikanderNawaz

        Great way to get it done as i required, one  project we are about to do  in android is that  making one pc as server with live ip and other clients that are  android phones are connected to the server , please  sir can you guide me about that,  i mean some guide lines to start or some  appropriate tutorials  ..please

  • Louis

    hi Mujtaba
    Could you please tell me how to import the AndroidServer into Aptana in detail?

  • alpha

    Hi Mujtaba,
    I have been following the path of the example above, but still there are mistakes. message in LogCat = “StnpClient : request time failed: java.net.SocketException:
    Address family not supported by protocol”

    can you help me

    thanks

    • http://www.hassanpur.com/ mujtaba

      Looks like you need to give your app permission to access the Internet. Make sure you have the following line in your AndroidManifest.xml file:

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

      I was able to reproduce your issue by commenting out that line and then running the app in the simulator.

  • Pingback: Importing Hassanpur.com example projects into Eclipse and Aptana | Hassanpur.com

  • http://profiles.google.com/quyendt2612 Quyen DamTran

    Hi!
    You can tell me how i can move server.php to my localhost.

    SERVER_URL = “http://www.hassanpur.com/AndroidListServer/server.php”

    I tried replacing it by: SERVER_URL = “http://localhost/server.php”

    but it doesnot work. thanks ^^!

    • Anonymous

      Assuming you have your server working and server.php is located in the root of your web server, you’ll need to change SERVER_URL to point to your server’s IP address. Keep in mind that localhost will resolve to the client’s IP address, so it won’t work.

      • http://profiles.google.com/quyendt2612 Quyen DamTran

        thanks for helping. i found my mistake. i forgot that my server hasn’t install php5 yet :D

      • http://profiles.google.com/quyendt2612 Quyen DamTran

        Ah, i know what you mean. when i try SERVER_URL = “http://localhost/server.php”
        its not work. but when i try SERVER_URL = “http://192.168.1.6/server.php”
        it works.

        and i have a question is how can i localize it. i want to use the first one “…localhost…”
        so when i bring it to another computer, i can run it normally.
        Thanks!

        • Anonymous

          I see what you’re trying to do, but this isn’t possible. The problem is that when you use localhost in the Android client, the client will attempt to connect to itself instead of the server. You need to use an IP address or a domain name to connect to the server. You’ll also have to change the SERVER_URL every time the server’s location changes, such as when moving it to another computer.

          • http://profiles.google.com/quyendt2612 Quyen DamTran

            Thanks!

  • Sinc Yossapong

    I run application success but when program start had pop up said “Sorry The application AndroidListClient(process com.AndroidListClient) has stopped unexpectedly Please try again” how to fix that

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      @8f6cf5424eb9dc5a37ca1d849da48a52:disqus What kind of exception did the application encounter? 

      • Sinc Yossapong

        I can run already , i forget change packet in manifest

  • Eugene Wechsler

     Hi. I am porting one Midlet app to Android and it’s my first Android APP. I was googling for good recomendations on Android client-server app. Your post appears to be very informative for me not just because of its content but because of reference to article about paintless threading by Google, where I found excelent link to Shelves project repository. Your post can be used as prototype but those real sources of Shelves shows how real things could be done. I’d recommend to every ametur to look into those sources.I was googling for good recomendations on Android client-server app. Your post appears to be very informative for me not just because of its content but because of reference to article about paintless threading by Google, where I found excelent link to Shelves project repository. Your post can be used as prototype but those real sources of Shelves shows how real things could be done. I’d recommend to every ametur to look into those sources.

  • Iroshan Horathalge

    Good example,Keep on writing.

    • Sibin

      Can anybody help please…….
      i want to create an app for a magazine, each moth the new updation will publish in my app..
      how to do it?
      and how to arrange each pages?? 

  • Pallavi

    Hello,once i finished deploying iam getting an error like this- “Sorry The application AndroidListClient(process com.AndroidListClient) has stopped unexpectedly Please try again” could anyone help me in fixing this.Please reply…………………..

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      Sorry for the late response. Can you provide some more info on the failure? The most likely reason I’ve seen for this is forgetting to give the app permission to access the Internet. Make sure that permission is listed in your AndroidManifest.xml file.

      • Pallavi

        Sir,i have given permission to access the Internet,i think the problem is with xml file,can i know from where can i download the xml required for this application?………………………………. 

        • http://www.hassanpur.com/ Mujtaba Hassanpur

          The AndroidManifest.xml file is located here: http://code.google.com/p/hassanpurcom/source/browse/trunk/android/AndroidListClientExample/AndroidManifest.xml

          • Pallavi

            Sir,not the AndroidManifest.xml file,i need list.xml file,when i got an error i had changed R.layout.list to R.layout.main in the following declaration ArrayAdapter adapter = new ArrayAdapter(this, R.layout.list, initialList);,i could only correct the error by doing this,actual application didn’t work…………plz send me the link of the list.xml……………………………

          • http://www.hassanpur.com/ Mujtaba Hassanpur

            Take a look at the Google Code repository. You can browse through all of the files there. The list.xml file is located there too.

          • Pallavi

            Thanks a lot sir,now it’s working……………………..

  • Zonzon

    I downloaded code of you from svn but when debug,   line
    DataOutputStream dataOut = new DataOutputStream(connection.getOutputStream()); 
    occur error . Logcat  :
    java.net.unknownhostexception host is unresolved .

  • Pingback: Implementeren client/server communicatie android « Indoor Navigation

  • Simson Raj 007

    i am new to android  plz help me how to do client server program i.e two numbers are given as input and it invokes the addition program from apache webserver (jsp) and shows the result please help me and mail me to simson.raj.007@gmail.com, thanks in advance

  • androidbeginner

    nicely done. Thank you. This was very helpful.

  • http://profile.yahoo.com/LUWZ4GT4YKOYDSBFTIE7IDVE5E Akiff Kasban

    Hi, at the start  of the article, you said that if we used Web Services, we could make XML -RPC calls. 
    If i wanted to make XML RPC calls to a Web Service, can it be done in the same way as what this tutorial teaches? 

    Thanks,
    Akiff

  • Shannon

    Hey,

    Would you mind providing a download of the working eclipse (assuming you’re using eclipse) project?  I like to import sample application in eclipse because I get to see them in their natural state and I understand how they work much better.  

    Thanks. :-)

  • Shannon

    LOL… Nevermind… Just saw the SVN google check out.  thanks. :-)

  • Saliyev Sanzhar

    I can not connect to the URL I have entered….

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      Can you connect to the URL in an external browser?

  • Jules Colle

    I get this error:  android.widget.ListView cannot be cast to android.widget.TextView

    I’ve read that you somehow have to override the getView() method of the ArrayAdapter class and let it return the expected view. But I’m not sure how to do this, and I’m not sure either why anybody else has encountered this problem…

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      Thanks, glad to see you got it working!

  • Saliyev Sanzhar

    Can anybody help please..
    I am using your tutorial to connect db, retrive something and ets..
    it is fine working for me….. 
    now I want to insert data into table…. it will work with out any exceptionsss…
    I posted my ServerInterface java class and php script….

    //ServerInterface.java
    public static void toOrder(String user_id,String order_name, String status)        {            String request = “command=” + URLEncoder.encode(“toorder”);         request+=”&user_id=” + URLEncoder.encode(user_id);         request+=”&order_name=” + URLEncoder.encode(order_name);         request+=”&status=” + URLEncoder.encode(status);                 Log.w(“server interfacereq”,request);                     try {                    URL url = new URL(SERVER_URL);                    URLConnection connection = url.openConnection();                                       /*                     * We need to make sure we specify that we want to provide input and                     * get output from this connection. We also want to disable caching,                     * so that we get the most up-to-date result. And, we need to                     * specify the correct content type for our data.                     */                    connection.setDoInput(true);                    connection.setDoOutput(true);                    connection.setUseCaches(false);                    connection.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);                    // Send the POST data                    DataOutputStream dataOut = new DataOutputStream(connection.getOutputStream());                    dataOut.writeBytes(request);                    dataOut.flush();                    dataOut.close();            } catch (IOException e) {                                       e.printStackTrace();            }        }
    // php script

  • Tirtha Msit

    Suppose,I want to create an application,where my web-server(which will be connected to database server) will send a request to my Android(Client) phone for enabling Voice Recorder Services.What I want to know :
     1> How will my Web-Server make a request/response (Will it be HTTP or something else..)to connect with my Android phone ?

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      This is a complicated situation because in this particular case, your web-server is initiating the request, so it is actually acting as a “client” and your Android device is responding to the request, so in this case it is taking the role of the “server”. The real challenge is how do you get the Android device to act as a server? Mobile devices aren’t designed to take the role of the server. That’s not to say that you can’t do this. You probably can, but I wouldn’t advise it.

      A better approach would be to use some sort of a polling method and have the Android device initiate the request to check for a status or command from the server on a regular basis. Note: This method consumes significantly more bandwidth, but it lets the Android device act as the “client”.If you still want to have the Android device act as a “server”, you’ll need to address numerous challenges, some of which are listed below:1. Your web-server needs to know the IP address of the Android device. The IP address can change depending on the Wi-Fi network you’re connected to or the IP address that the phone service provider assigns you. You can work around this by sending a request from your Android device to the web server whenever the IP address changes, but it won’t be very reliable.

      2. Depending on the Wi-Fi network you’re connected to or the service provider, you may find that the port you are listening for requests on is blocked by the network firewall. I don’t see a good workaround for this one.

      3. Having your device act as a server means always running a service to accept requests. This will consume a lot of power and drain the device’s battery quickly.

  • http://www.zudownload.com/ Selji Okita

    I can do it! Thank you. This post was helpful. Can I repost it to my blog? I will post backlink!

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      Thanks, glad to see it worked for you! I would prefer links to the article, as opposed to copying the information.

      • http://fbvn.info/ Facebook Việt Nam

        Of course, if I reblog this post, I will post source link! Thank you!

        • Vts

          I think that Hassanpur would like you to link to this article, not to reblog the content

          • http://fbvn.info/ Facebook Việt Nam

             Ok thank you!

  • Vts

    Thank you for great articles like this. 

  • Lau

    Do you have any idea why I receive this message: “System.err(15491): java.net.ConnectException: localhost/127.0.0.1:80 – Connection refused” ? I added the Internet permission to the manifest and i’m sure it’s working, as I am using Google maps in my app and I’ve tested the script too, it is also working. Thanks a lot!

  • Adrião Neves

    Nice and clean! Thank you very much!

  • TheShadow

    Hello, I really like your example, but I have a problem with connecting to localhost. I made my SERVER_URL = “http://192.168.*.*/server.php but I cannot connect I get the connection timeout exception. Please help me to connect to my localhost I’m using XAMPP.
    Thanks in advance!

  • PGP_Protector

    New to Android Development, but when I try this I’m getting a warning that readLine is deprecated (inputLine = dataIn.readLine())

    I think this is the fix (Still coding and trying it)

    BufferedReader bufferedIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));        String newInputLine;        while((newInputLine = bufferedIn.readLine()) !=null){result +=newInputLine;}        bufferedIn.close();

  • Mohdazeem110

    sir! i done as you said…but when i run it it shows a black list…sir plz tell me where i am lacking??? 

  • Mohdazeem110

    sir! i done as you said…but when i run it. it shows a blank list…sir plz tell me where i am lacking???

    • http://www.hassanpur.com/ Mujtaba Hassanpur

      It’s difficult to determine the problem without additional details. What kind of error(s) are you seeing in the logs? Which web server are you pointing to? Is the webserver reachable from your mobile device?

  • Corin Duttoni

    Hi, I’m looking into your code right now because it seems the closest to what I would need for my app to communicate with a server. Would it be possible though if you could provide a tutorial on how I can make my PhoneGap-powered Android app (using a local PHP) to communicate to a remote PHP file that would connect to a MySQL database in a server and return the data needed?

  • arezoo

    hello
    thanks for great topics, hope you to continue that.

    I’m trying to build an application witch in user can see a list of voices that are uploaded somewhere and he/she can download each voice by clicking on it’s name in list.
    how can I create and connect to database?

  • Shashwat

    Do i need to purchase a domain for setting up the server?

  • Mohammed Sadiq

    Hello Mujtaba,

    This is a very interesting blog which helped me a lot and can you please help me with an example to connect to DB through PHP script to read and write data to or from android app.

    Thanks and regards,
    Mohammed Sadiq

  • Bilal Sarwar

    How to handle more than one client, can be said 8 or more

  • http://note-us.com Jono

    Thank you, you have a really interesting and informative site forming. This article was exactly what i was looking for. Keep us the good work

  • anil yadav

    nice!