Project Overview
This post will describe simple client-server communications between an Android app and a web service using REST techniques, particularly GET and POST. For this demo, we will be sending and receiving data for a simple Java class called Person, which includes a firstName, lastName and email address. The data stored in an instance of this class will be transmitted from our web service in JSON format.
NOTE: This post is a work in progress and will be updated and corrected, as time permits.
Prerequisites
This demo assumes that you have a version of Eclipse that can create a “Dynamic Web Project”, and that you have an instance of the Tomcat servlet container that you can control through Eclipse. This demo also assumes that you have the Android SDK, at least one Android Virtual Device (AVD), and have the Eclipse ADT plugin.
Another important requirement is that your Android device needs to be on the same network as your Tomcat server. The simplest way to do this would be to make sure you are running your emulator on the same computer that is running Tomcat.
About REST
REST – “Representational State Transfer” is a technique that makes use of standard web protocols for the implementation of a web service. A RESTful web service uses the standard HTTP GET PUT DELETE and POST actions to submit, retrieve or modify server-side data.
Commonly, in a REST web service, the standard HTTP actions are used as follows:
- GET – retrieves or queries for data, usually using passed criteria
- PUT – creates a new entry, record
- DELETE – removes a resource
- POST- updates a resource or creates a resource
The data that is transmitted uses standard MIME types, including images, video, text, html, XML and JSON.
A key feature of a REST service is its use of URI paths as query parameters. For example, a fictional web service for a book library might return a list of Civil War history books with this URI:
http://librarywebservice.com/books/history/CivilWar
Or, for magazines about tennis:
http://librarywebservice.com/magazines/sports/tennis
These are the absolute basics. REST has become a very popular replacement to SOAP for the development of web services.
Download the Jersey Jars
For the web server, this demo will use Tomcat, and will make use of a reference implementation of the JSR 311 Java library, otherwise known as “jersey”. The Jersey API can significantly streamline the development of a RESTful web service, and much of its ease comes from the use of annotations.
The home page, and the place to download the required jars for jersey can be found here. As of the writing of this post, the jars will be found in a zip called jersey-archive-1.12.zip . Please download this zip and expand it to a folder where you can find those jars.
Create a “Dynamic Web Project” in Eclipse
In Eclipse, select “File”->”New…”->”Project” and use the filter to find “Dynamic Web Project”

I have Apache Tomcat 7 running on my laptop, and have previously configured a connection between Tomcat and Eclipse. The Dynamic web module version I am using is 3.0, but this tutorial can work with version 2.5.

Click “Next” and define your context root. That is the starting-point URL for your web service. With the context root shown in the screenshot below, the resulting URL on my laptop will be http://localhost:8080/RestWebServiceDemo . Also, have Eclipse generate a web.xml deployment descriptor.

Add Jersey Jars to Project
You will need to import the jars that you’ve downloaded from http://jersey.java.net into the WEB-INF/lib folder. Right click that folder (WebContent/WEB-INF/lib) and select Import…

I’ve simply thrown in all the jars into that folder for the purposes of this tutorial. Crude, but effective. The smart thing would be to only use the jars you need. I’ll eventually circle back to that some day.

Update Project Build Path to Include Jersey Jars
Now that the jars are in the WEB-INF/lib folder, you will need to configure the project to include these jars in its build path. From within your project in the Package Explorer on the left of your Eclipse screen, right click to select “Build Path”->”Configure Build Path…”
On the “Libraries” tab, click on “Add External JARS…” and select the jars that are now in your project’s WEB-INF/lib path.

Create the POJO Person class
Within the \src folder, create a package called com.avilyne.rest.model, and in that package, create a Java class called Person. Note, in the code shown below, the @XmlRootElement annotation. This tells Jersey that this would be the root object of any generated XML (or JSON) representation of this class. This might not be very useful for this class, but if you had a compound class, you’d be able to control what the XML or JSON output would look like by the addition of annotations like this.
package com.avilyne.rest.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Person {
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Person() {
id = -1;
firstName = "";
lastName = "";
email = "";
}
public Person(long id, String firstName, String lastName, String email) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
private long id;
private String firstName;
private String lastName;
private String email;
}
Create the PersonResource class
Again, in the \src folder, create a new package called com.avilyne.rest.resource, and in that package create a class called PersonResource. (We are separating our data model from our controller).
The PersonResource class will be the interface between a Person object and the web. When a client requests a Person object, the PersonResource will handle the request and return the appropriate object.
Note, in the code below, the annotations. The @Path(“/person”) annotation allows us to define the URI that will have access to this resource. It will be something along the lines of http://RestServerDemo/rest/person, but this will be explained in more detail as we map this code in our web.xml file.
The @Context annotation allows us to inject, in this example, UriInfo and Request objects into our PersonResource object. Our code can inspect those injected objects for any desired Context information.
// The @Context annotation allows us to have certain contextual objects // injected into this class. // UriInfo object allows us to get URI information (no kidding). @Context UriInfo uriInfo; // Another "injected" object. This allows us to use the information that's // part of any incoming request. // We could, for example, get header information, or the requestor's address. @Context Request request;
The @GET annotation lets us specify what method will be called when a client issues a GET to the webservice. Similar logic applies to the @POST annotation. Note that the actual method name will not be a part of the client’s URI.
Also note that more than one method has a @GET annotation. The first @GET is simply there so that, when we start our service, we can use a browser to retrieve some sort of response that indicates the service is running. Technically, instead of producing TEXT_PLAIN, the first GET could have produced a TEXT_HTML page.
// Basic "is the service running" test
@GET
@Produces(MediaType.TEXT_PLAIN)
public String respondAsReady() {
return "Demo service is ready!";
}
The @Path annotation lets us append a parameter onto our URI. Using the example from earlier, the hypothetical URI would be http://RestServerDemo/rest/person/sample .
@GET
@Path("sample")
@Produces(MediaType.APPLICATION_JSON)
public Person getSamplePerson() {
System.out.println("Returning sample person: " + person.getFirstName() + " " + person.getLastName());
return person;
}
Note that paths do NOT need to be literal. One can have a path parameter as a variable, e.g. @Path(“{id}”) would refer to a person whose id value matched the passed URI value. http://RestServerDemo/rest/person/1 should return a person whose id is 1.
The @Produces annotation allows us to define how the output from our resource should be transmitted to our client. Note that, for the getSamplePerson() method, we return a person object, and the annotation lets us tell Jersey to format and transmit that person as a JSON object.
The method with the @POST annotation also includes a @Consumes annotation. As you can guess, this method is called in response to a client’s POST request. The data for the “person” object being transmitted from the client is not a JSON object, but is a collection of Name-Value pairs. The @Consumes annotation allows us to specify that the data passed from the client is an array of these pairs, and we can pull out the values we want from that array.
// Use data from the client source to create a new Person object, returned in JSON format.
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Person postPerson(
MultivaluedMap<String, String> personParams
) {
String firstName = personParams.getFirst(FIRST_NAME);
String lastName = personParams.getFirst(LAST_NAME);
String email = personParams.getFirst(EMAIL);
System.out.println("Storing posted " + firstName + " " + lastName + " " + email);
person.setFirstName(firstName);
person.setLastName(lastName);
person.setEmail(email);
System.out.println("person info: " + person.getFirstName() + " " + person.getLastName() + " " + person.getEmail());
return person;
}
For each of the methods in this PersonResource, I’ve added a System.out.println() as a crude way of letting us see when a request is being processed. There are probably more elegant ways of doing this (Logging, for one), and one would almost never include a System.out.println in a production service. This is just a demo.
package com.avilyne.rest.resource;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Request;
import com.avilyne.rest.model.Person;
@Path("/person")
public class PersonResource {
private final static String FIRST_NAME = "firstName";
private final static String LAST_NAME = "lastName";
private final static String EMAIL = "email";
private Person person = new Person(1, "Sample", "Person", "sample_person@jerseyrest.com");
// The @Context annotation allows us to have certain contextual objects
// injected into this class.
// UriInfo object allows us to get URI information (no kidding).
@Context
UriInfo uriInfo;
// Another "injected" object. This allows us to use the information that's
// part of any incoming request.
// We could, for example, get header information, or the requestor's address.
@Context
Request request;
// Basic "is the service running" test
@GET
@Produces(MediaType.TEXT_PLAIN)
public String respondAsReady() {
return "Demo service is ready!";
}
@GET
@Path("sample")
@Produces(MediaType.APPLICATION_JSON)
public Person getSamplePerson() {
System.out.println("Returning sample person: " + person.getFirstName() + " " + person.getLastName());
return person;
}
// Use data from the client source to create a new Person object, returned in JSON format.
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Person postPerson(
MultivaluedMap<String, String> personParams
) {
String firstName = personParams.getFirst(FIRST_NAME);
String lastName = personParams.getFirst(LAST_NAME);
String email = personParams.getFirst(EMAIL);
System.out.println("Storing posted " + firstName + " " + lastName + " " + email);
person.setFirstName(firstName);
person.setLastName(lastName);
person.setEmail(email);
System.out.println("person info: " + person.getFirstName() + " " + person.getLastName() + " " + person.getEmail());
return person;
}
}
Create or Edit the WebContent\WEB-INF\web.xml file
In our web.xml file, we want to direct all requests to a servlet called Jersey REST Service. We will also tell this service where to find the resources that we want to make available to our client app.
Update the web.xml file (or create it, in WebContent\WEB-INF\web.xml, if it does not exist) to match the XML shown below.
The XML defines the Jersey REST Service from the com.sun.jersey.spi.container.ServletContainer class. That class, as you might guess, is in one of the Jersey Jars. The init-param section allows us to tell that servletcontainer to use the classes found in the com.avilyne.rest.resource package for the mapping of URIs to java code.
In the servlet-mapping section, we create a global url-pattern, which essentially says that any request that goes to /rest/ will attempt to be mapped to the appropriate methods.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>JerseyRESTServer</display-name> <servlet> <servlet-name>Jersey REST Service</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.avilyne.rest.resource</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey REST Service</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>
Run the WebService
Run the completed project as a service on your Tomcat servlet container. The actual URL for the service will vary slightly, depending partly on the name of your project. I called my project JerseyRESTServer, and here is the URL for the web service on my computer:
http://localhost:8080/JerseyRESTServer/rest/person
Correction! Paul, a recent commenter, has pointed out that the URL should actually be:
http://localhost:8080/RestWebServiceDemo/rest/person
RestWebServiceDemo is the context root that we defined when we first started this project. I’ll mention that I built a few versions of this project before writing this post, so unfortunately some of the images show a URL from an earlier version of the project.
If I bring up this on a browser, it returns with this:

If I add the “sample” path to the URL, like this:
http://localhost:8080/RestWebServiceDemo/rest/person/sample
The web service returns a JSON object:
{"email":"sample_person@jerseyrest.com","firstName":"Sample","id":"1","lastName":"Person"}
I would recommend that you make sure you can retrieve this sample person before you create the Android client app.
Create an Android Client App
Create a new Android project, calling it something like AndroidRESTClient. I used API level 10 for this project, but one can probably use a lower level API, if required. Android HttpClient requests have been around since the earliest days of the OS. Use com.avilyne.android as the package for the main activity.
Edit the \res\layout\main.xml File
The interface will be very simple, having three labels and three edit controls for firstName, lastName and email address. It will also have three buttons – one to GET, one to POST, and one to clear the controls.
The main.xml file should look like this:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tableLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:shrinkColumns="*"
android:stretchColumns="*" >
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
style=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/firstName" >
</TextView>
<EditText
android:id="@+id/first_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textCapWords"
android:layout_span="2" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
style=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lastName" >
</TextView>
<EditText
android:id="@+id/last_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textCapWords"
android:layout_span="2" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
style=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/email" >
</TextView>
<EditText
android:id="@+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:layout_span="2" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/bn_retrieve"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="retrieveSampleData"
android:text="@string/retrieve" />
<Button
android:id="@+id/bn_post"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="postData"
android:text="@string/post" />
<Button
android:id="@+id/bn_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clearControls"
android:text="@string/clear" />
</TableRow>
</TableLayout>
Note that an onClick method is defined for each button.
Edit the \res\values\strings.xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="firstName">First Name</string>
<string name="lastName">Last name</string>
<string name="email">Email</string>
<string name="retrieve">Retrieve</string>
<string name="post">Post</string>
<string name="clear">Clear</string>
<string name="app_name">AndroidRESTClient</string>
</resources>
Edit the AndroidRESTClientActivity.java file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="firstName">First Name</string>
<string name="lastName">Last name</string>
<string name="email">Email</string>
<string name="retrieve">Retrieve</string>
<string name="post">Post</string>
<string name="clear">Clear</string>
<string name="app_name">AndroidRESTClient</string>
</resources>
Edit the AndroidRESTClientActivity.java file
Discuss the WebServiceTask, and the handleResponse() method.
The full source code for the Android client is listed below, but I want to highlight a few items in the code that you should be aware of. On my home network, the computer running the service on Tomcat is at IP address 192.168.1.9. On your network, the address will most definitely be different. If you are running the Android client and the Tomcat service on the same computer, you can get away with using “localhost” in your Android code.
(CORRECTION: (Thanks ABa) Actually, you *can’t* use “localhost”. “Localhost” in this context would refer to the Android device itself. Use the IP address of the computer on your network that is running the Tomcat service. See this StackOverflow link for details.)
public class AndroidRESTClientActivity extends Activity {
private static final String SERVICE_URL = "http://192.168.1.9:8080/RestWebServiceDemo/rest/person";
For this tutorial, the most important code is the internal “WebServiceTask” class, which is extended from an “AsyncTask” class. An AsyncTask class descendant allows a process to run in a separate thread. If our communication with our service were on the Android app’s main thread, the user interface would lock up as the process was waiting for results from the server.
One can define the types of parameters that are passed to one’s instance of the AsyncTask. (more on that later). The communication with the web service occurs in the WebServiceTask’s “doInBackground()” code. This code uses Android’s HttpClient object, and for the GET method, uses HttpGet, and for the POST method, uses HttpPost.
The AsyncTask class includes two other methods that one has the option to overwrite. One is onPreExecute(), which one can use to prepare for the background process, and the other is onPostExecute(), which one can use to do any required clean-up after the background process is complete. This code overrides those methods to display and remove a progress dialog.
The background task also includes two timeout options. One is a timeout period for the actual connection to the service, and the other is a timeout period for the wait for the service’s response.
package com.avilyne.android;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
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.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;
public class AndroidRESTClientActivity extends Activity {
private static final String SERVICE_URL = "http://192.168.1.9:8080/RestWebServiceDemo/rest/person";
private static final String TAG = "AndroidRESTClientActivity";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void retrieveSampleData(View vw) {
String sampleURL = SERVICE_URL + "/sample";
WebServiceTask wst = new WebServiceTask(WebServiceTask.GET_TASK, this, "GETting data...");
wst.execute(new String[] { sampleURL });
}
public void clearControls(View vw) {
EditText edFirstName = (EditText) findViewById(R.id.first_name);
EditText edLastName = (EditText) findViewById(R.id.last_name);
EditText edEmail = (EditText) findViewById(R.id.email);
edFirstName.setText("");
edLastName.setText("");
edEmail.setText("");
}
public void postData(View vw) {
EditText edFirstName = (EditText) findViewById(R.id.first_name);
EditText edLastName = (EditText) findViewById(R.id.last_name);
EditText edEmail = (EditText) findViewById(R.id.email);
String firstName = edFirstName.getText().toString();
String lastName = edLastName.getText().toString();
String email = edEmail.getText().toString();
if (firstName.equals("") || lastName.equals("") || email.equals("")) {
Toast.makeText(this, "Please enter in all required fields.",
Toast.LENGTH_LONG).show();
return;
}
WebServiceTask wst = new WebServiceTask(WebServiceTask.POST_TASK, this, "Posting data...");
wst.addNameValuePair("firstName", firstName);
wst.addNameValuePair("lastName", lastName);
wst.addNameValuePair("email", email);
// the passed String is the URL we will POST to
wst.execute(new String[] { SERVICE_URL });
}
public void handleResponse(String response) {
EditText edFirstName = (EditText) findViewById(R.id.first_name);
EditText edLastName = (EditText) findViewById(R.id.last_name);
EditText edEmail = (EditText) findViewById(R.id.email);
edFirstName.setText("");
edLastName.setText("");
edEmail.setText("");
try {
JSONObject jso = new JSONObject(response);
String firstName = jso.getString("firstName");
String lastName = jso.getString("lastName");
String email = jso.getString("email");
edFirstName.setText(firstName);
edLastName.setText(lastName);
edEmail.setText(email);
} catch (Exception e) {
Log.e(TAG, e.getLocalizedMessage(), e);
}
}
private void hideKeyboard() {
InputMethodManager inputManager = (InputMethodManager) AndroidRESTClientActivity.this
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(
AndroidRESTClientActivity.this.getCurrentFocus()
.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
private class WebServiceTask extends AsyncTask<String, Integer, String> {
public static final int POST_TASK = 1;
public static final int GET_TASK = 2;
private static final String TAG = "WebServiceTask";
// connection timeout, in milliseconds (waiting to connect)
private static final int CONN_TIMEOUT = 3000;
// socket timeout, in milliseconds (waiting for data)
private static final int SOCKET_TIMEOUT = 5000;
private int taskType = GET_TASK;
private Context mContext = null;
private String processMessage = "Processing...";
private ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
private ProgressDialog pDlg = null;
public WebServiceTask(int taskType, Context mContext, String processMessage) {
this.taskType = taskType;
this.mContext = mContext;
this.processMessage = processMessage;
}
public void addNameValuePair(String name, String value) {
params.add(new BasicNameValuePair(name, value));
}
private void showProgressDialog() {
pDlg = new ProgressDialog(mContext);
pDlg.setMessage(processMessage);
pDlg.setProgressDrawable(mContext.getWallpaper());
pDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pDlg.setCancelable(false);
pDlg.show();
}
@Override
protected void onPreExecute() {
hideKeyboard();
showProgressDialog();
}
protected String doInBackground(String... urls) {
String url = urls[0];
String result = "";
HttpResponse response = doResponse(url);
if (response == null) {
return result;
} else {
try {
result = inputStreamToString(response.getEntity().getContent());
} catch (IllegalStateException e) {
Log.e(TAG, e.getLocalizedMessage(), e);
} catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage(), e);
}
}
return result;
}
@Override
protected void onPostExecute(String response) {
handleResponse(response);
pDlg.dismiss();
}
// Establish connection and socket (data retrieval) timeouts
private HttpParams getHttpParams() {
HttpParams htpp = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(htpp, CONN_TIMEOUT);
HttpConnectionParams.setSoTimeout(htpp, SOCKET_TIMEOUT);
return htpp;
}
private HttpResponse doResponse(String url) {
// Use our connection and data timeouts as parameters for our
// DefaultHttpClient
HttpClient httpclient = new DefaultHttpClient(getHttpParams());
HttpResponse response = null;
try {
switch (taskType) {
case POST_TASK:
HttpPost httppost = new HttpPost(url);
// Add parameters
httppost.setEntity(new UrlEncodedFormEntity(params));
response = httpclient.execute(httppost);
break;
case GET_TASK:
HttpGet httpget = new HttpGet(url);
response = httpclient.execute(httpget);
break;
}
} catch (Exception e) {
Log.e(TAG, e.getLocalizedMessage(), e);
}
return response;
}
private String inputStreamToString(InputStream is) {
String line = "";
StringBuilder total = new StringBuilder();
// Wrap a BufferedReader around the InputStream
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
try {
// Read response until the end
while ((line = rd.readLine()) != null) {
total.append(line);
}
} catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage(), e);
}
// Return full string
return total.toString();
}
}
}
(Code discussion, with excerpts, here)
Update the AndroidManifest.xml
Since this app needs to communicate via the internet, one must give the app the appropriate permissions.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.avilyne.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AndroidRESTClientActivity"
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>
</manifest>
Running the Android Client App
This screenshot shows the Android client app with its blank screen.

If one presses the “Retrieve” button, the web service will respond:

The Android client’s controls should get populated with the retrieved Person:

Here I’ve modified the values on my Android client screen, and pressed the “Post” button:

The web service responds to the post:

Hopefully, this will give you some idea of how to build an Android client that communicates with a web service using REST.

Hi! Thanks for this great article!
I tried localhost, but this doesn’t work on the emulator. You’ve got to use http://10.0.2.2:8080 instead. See post at http://stackoverflow.com/questions/4905315/error-connection-refused
ABa
Thanks for the comment regarding the use of “localhost” within the emulator. The link you posted is correct, of course, in that the emulator runs within its own VM, so “localhost” would refer to the Android device itself.
For the purposes of this demo, it might be best to point to the IP of the computer on one’s network that is functioning as the server.
I’ll update this post accordingly.
Mark
use your system IP address instead of local host in source code
For what it’s worth: I had to change all the URL’s to use the Web Module’s Context Root name to get this to work, e.g. change from “http://localhost:8080/JerseyRESTServer/rest/person” to “http://localhost:8080/RestWebServiceDemo/rest/person”.
Otherwise a great tutorial … a big help getting started!!! Thanks a lot for posting this.
Paul
Paul: Great catch on that context root issue. I had built several versions of this little project before writing up this post. It is now apparent that my screen captures were from more than one version.
I’ll update this post to reflect the corrections you’ve mentioned.
Mark
Still got error 404 when I run this
http://localhost:8080/RestWebServiceDemo/rest/person
I don’t know what happen,
I haven’t already yet try to code the android side.
404 is “not found”, which means the server is up, but it can’t find anything at that url. What is your project’s “Context root”? We’ll start from there.
Also, if you’d be willing to post your web.xml, I might be able to help by looking at that.
My “Context Root” is Luna, I’d already try the same way with http://localhost:8080/Luna/rest/person
Here is my web.xml, I try to code the same as yours. and so about the other java class Person and PersonResource.
Luna
Jersey REST Service
com.sun.jersey.spi.container.servlet.ServletContainer
com.sun.jersey.config.property.packages
com.avilyne.rest.resource
1
Jersey REST Service
/rest/*
I think this might be the problem, when I try to run on Tomcat, by right click my Project “Luna” then Run on Server, then I choose the Tomcat 7.0 that I’d already create.
It appears diaolog box like this.
“Starting tomcat has encountered a problem, server tomcat failed to start”
and in my console it appears like this
Jun 21, 2012 7:49:11 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:Program FilesJavajre7bin;C:WindowsSunJavabin;C:Windowssystem32;C:Windows;C:/Program Files/Java/jre7/bin/client;C:/Program Files/Java/jre7/bin;C:/Program Files/Java/jre7/lib/i386;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:Program FilesATI TechnologiesATI.ACECore-Static;C:Program FilesWIDCOMMBluetooth Software;C:Program FilesJavajdk1.6.0_16bin;C:Program FilesJavajdk1.7.0_01bin;C:opencvbuildcommontbbia32vc10;C:opencvbuildx86vc10bin;C:Serverapache-tomcat-6.0.26bin;;D:ProgimaEclipse JEE Indigoeclipse;;.
Jun 21, 2012 7:49:11 AM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source’ to ‘org.eclipse.jst.jee.server:Luna’ did not find a matching property.
Jun 21, 2012 7:49:12 AM org.apache.coyote.AbstractProtocolHandler init
INFO: Initializing ProtocolHandler [\"http-bio-8080\"]
Jun 21, 2012 7:49:12 AM org.apache.coyote.AbstractProtocolHandler init
INFO: Initializing ProtocolHandler [\"ajp-bio-8009\"]
Jun 21, 2012 7:49:12 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 612 ms
Jun 21, 2012 7:49:12 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Jun 21, 2012 7:49:12 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.12
java.lang.IllegalAccessError: class com.sun.media.sound.AbstractPlayer cannot access its superclass com.sun.media.sound.AbstractMidiDevice
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1591)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1521)
at org.apache.catalina.startup.ContextConfig.checkHandlesTypes(ContextConfig.java:1956)
at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:1919)
at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:1806)
at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1765)
at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1751)
at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1255)
at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:882)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:317)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:89)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5081)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1033)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:774)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1033)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:291)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:727)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.startup.Catalina.start(Catalina.java:620)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:303)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:431)
I might be chasing the wrong thing, but in the trace that you’ve posted, I find this:
“java.lang.IllegalAccessError: class com.sun.media.sound.AbstractPlayer cannot access its superclass com.sun.media.sound.AbstractMidiDevice
”
Maybe there’s an incorrect jar file in your project?
Perhaps the best way to diagnose this would be for me to see the other project components.
I have also the same problem as AdityaSetyadi, please suggest me how to resolve.
I just want to tell you that this is a wonderful article! you are great!
Very kind words. I hope to post more.
Howdy! This is my first visit to your blog!
We are a group of volunteers and starting a new project
in a community in the same niche. Your blog provided us beneficial information to work
on. You have done a marvellous job!
Highly energetic post, I liked that a lot. Will there be a part 2?
it is realy very good post it much helpfull to me
This is really a very good post and helpful for me
If you want to access the Tomcat service which running on your PC from your Android device via your wireless network, first run the command ipconfig on your the command window of your PC (in Windows 7 use run (Windows logo + R), cmd, ipconfig).
Note the IPv4 address: (it should be 192.168.0.x) for some x. Use this as the server IP address, together with the port number, i.e. 192.168.0.x:8080, in your code, for example
private static final String SERVICE_URL = “http://192.168.0.7:8080/RestWebServiceDemo/rest/person”;
Your Android device will then access the server via your wireless network router.
All true. Thanks for your helpful comments, Michael.
Excellent article..Very useful for beginners like me.. Thanks a lot
Nice post – thanks
Awesome Tutorial Properly worked……
This is the best example I’ve found on dealing with RESTful services from the server side using Java with an Android client, and it was really helpful. Thanks a lot!
first_ name in (R.id.first_name) gives me an error, and so does last_name and email… why?
Does your layout include edit controls with those names? That’s the first thing I’d check, but I’ll also mention that if there’s an error *anywhere else* in your layout, your XML won’t compile, and the Android toolkit will not generate the required “R” values. This *might* account for the missing R.xxx error messages you are receiving.
I had same error . i removed to res/menu/main.xml to fix it.
i want to send the image to server through RESTFUL get method how to send when i send image by converting to string it is not taking my input how to send image to server please help me
You should probably convert your image to a byte [] array and create an encoded string from that array:
You could then upload that to your server via a POST. On the server side, you’d need to convert the received encoded string to a byte array and create an image from that.
I’m sure there are examples on StackOverflow.
Really awesome tutorial . We are bening to an android project using web service and it helps me a lot . Thank you very much
hi
tnx a lot for this tutorial,but i don’t know why i have this exception :java.lang.String cannot be converted to JSONObject in the line : JSONObject jso = new JSONObject(response);
can you help me to fix this problem pleaze?
It *might* be that the response value you’re getting back is not a String. I’d do two things:
1.) Step through this code with a debugger to find out what is in your returned response value.
2.) try: JSONObject jso = new JSONObject(response.toString())
You shouldn’t have to do item 2, but that might get you over the hump. I think the real issue is the format of the “response” value you’re receiving.
Great article! Thank you!
Awesome article thank you
I have copied the exact code for restful web service, while runnning it, if (http://localhost:8080/RestWebService/rest/person) i am also getting the same result:Demo service is ready!
but when i am trying (http://localhost:8080/RestWebService/rest/person/sample) i am getting the error : com.sun.jersey.api.MessageException: A message body writer for Java class com.polaris.webservice.Person, and Java type class com.polaris.webservice.Person, and MIME media type application/json was not found
Returning sample person: Sample Person
Well, I got the solution, i didn’t add @XmlRootElement previously..now it’s showing perfectly..and thanks for this wonderful tutorial.
Great tutorial, thx!
I’ve got one question:
‘Post’ should change the attributes of person with the entered values, but when I click on ‘Retrieve’ afterwards I get the original Values (Sample, Person, sample_person@jerseyrest.com) again.
What have I not considered?
Excellent question. In short, the updated data is not being stored. A complete implementation would include a persistence mechanism that would retrieve and store your updates in a database. It is also worth noting that each call to the servlet brings up a separate live instance of that servlet, which in this demo includes a Person object with hard-coded values, rather than being retrieved from a database. Now, if two people access the same Person object with the intent to update its values, there’s a potential for conflict there which would have to be handled on the server-side code.
The other day I encountered an interview question that asked how to handle that conflict. I stumbled through the question, but a solution would involve the use of ConcurrentHashMap. Among other features, it provides the equivalent of a relational database’s row locking mechanism.
This might be a great subject for a separate tutorial, slightly outside of the original scope of this mobile-centric blog, but worth considering. Scalable server side development for mobile apps is an area that I think needs more discussion.
Hi,
Thanks for a great but I am getting the 404 resource not found error. I’ve checked that the context root and the URL is the same i.e both contain RestWebserviceDemo.
The following is the error message I get when I run Tomcat Server:
11-Jan-2013 13:44:25 org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:Program FilesJavajre6bin;C:WindowsSunJavabin;C:Windowssystem32;C:Windows;C:/Program Files/Java/jre6/bin/client;C:/Program Files/Java/jre6/bin;C:/Program Files/Java/jre6/lib/i386; C:Program FilesJavajdk1.6.0_26/bin;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:UsersPoojaAppDataLocalSmartbarApplication;C:UsersPoojaAppDataLocalSmartbarApplication;C:apache-ant-1.8.4bin;C:apache-ant-1.8.4bin;C:Program FilesBitvise Tunnelier;C:Program FilesMATLAB1R2010bruntimewin32;C:Program FilesMATLAB1R2010bbin;C:Program FilesBitvise SSH Client;C:UsersPoojaDocumentseclipse;;.
11-Jan-2013 13:44:25 org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source’ to ‘org.eclipse.jst.jee.server:MyDMULibraryServer’ did not find a matching property.
11-Jan-2013 13:44:25 org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source’ to ‘org.eclipse.jst.jee.server:RestWebservice’ did not find a matching property.
11-Jan-2013 13:44:25 org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler [\"http-bio-8080\"]
11-Jan-2013 13:44:25 org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler [\"ajp-bio-8009\"]
11-Jan-2013 13:44:25 org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 719 ms
11-Jan-2013 13:44:25 org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
11-Jan-2013 13:44:25 org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.30
11-Jan-2013 13:44:27 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
com.example.rest.resource
11-Jan-2013 13:44:27 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version ‘Jersey: 1.12 02/15/2012 04:51 PM’
11-Jan-2013 13:44:27 com.sun.jersey.server.impl.application.RootResourceUriRules
SEVERE: The ResourceConfig instance does not contain any root resource classes.
11-Jan-2013 13:44:27 org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
at com.sun.jersey.server.impl.application.RootResourceUriRules.(RootResourceUriRules.java:99)
at com.sun.jersey.server.impl.application.WebApplicationImpl._initiate(WebApplicationImpl.java:1308)
at com.sun.jersey.server.impl.application.WebApplicationImpl.access$700(WebApplicationImpl.java:171)
at com.sun.jersey.server.impl.application.WebApplicationImpl$13.f(WebApplicationImpl.java:777)
at com.sun.jersey.server.impl.application.WebApplicationImpl$13.f(WebApplicationImpl.java:773)
at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)
at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:773)
at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:768)
at com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:488)
at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:318)
at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:607)
at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:208)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:373)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:556)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1266)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1185)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1080)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5027)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5314)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
11-Jan-2013 13:44:27 org.apache.catalina.core.StandardContext loadOnStartup
SEVERE: Servlet /RestWebserviceDemo threw load() exception
com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
at com.sun.jersey.server.impl.application.RootResourceUriRules.(RootResourceUriRules.java:99)
at com.sun.jersey.server.impl.application.WebApplicationImpl._initiate(WebApplicationImpl.java:1308)
at com.sun.jersey.server.impl.application.WebApplicationImpl.access$700(WebApplicationImpl.java:171)
at com.sun.jersey.server.impl.application.WebApplicationImpl$13.f(WebApplicationImpl.java:777)
at com.sun.jersey.server.impl.application.WebApplicationImpl$13.f(WebApplicationImpl.java:773)
at com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:193)
at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:773)
at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:768)
at com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:488)
at com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:318)
at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:607)
at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:208)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:373)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:556)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1266)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1185)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1080)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5027)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5314)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
11-Jan-2013 13:44:28 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler [\"http-bio-8080\"]
11-Jan-2013 13:44:28 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler [\"ajp-bio-8009\"]
11-Jan-2013 13:44:28 org.apache.catalina.startup.Catalina start
INFO: Server startup in 3083 ms
And the here is my web.xml:
RestWebserviceDemo
Jersey REST Service
com.sun.jersey.spi.container.servlet.ServletContainer
com.sun.jersey.config.property.packages
com.example.rest.resource
1
Jersey REST Service
/rest/*
Can you please help?
Thanks
This probably has to do with the mapping of the servlet in your web.xml file. When I first built this project I had a similar issue. Can you compare your servlet mapping to your package name?
It’s also possible that your code is not being copied to the right destination when you kick off a Tomcat run.
Hi Nice post. if i want to implement secure link (https)between the android and server how do I implement this? Thanks
Great question. I should figure this out myself, but I did find clues in this StackOverflow discussion:
http://stackoverflow.com/questions/2864016/httpclient-ssl-certificate-on-android
Sorry I can’t give you more than that.
Pingback: android access server database out of two choices
Pingback: android access server database out of two choices : Android Community - For Application Development
Hi!
I have a question, when you first retrieve the information you get the information of the sample person. Then I post information changing the info of the sample and when I retrieve after posting the new information, should I get the new information I just posted or is it ok if I am getting the information of the sample person. When I do it I am getting the information of the sample person but I thought you were using the post to update the info of the sample person.
Warm regards, was a very useful post
That’s a great question. Once your data is posted to the server, that data should actually be stored, mostly commonly in a database. I bypassed implementing a storage mechanism for the purposes of brevity. As you have probably realized, each time you interact with the server, a separate instance of that servlet is instantiated, and in my implementation, that instance creates a “hard coded” Person instance. In a real implementation, the servlet would retrieve the data from a database to populate that Person object.
Thank you, I figured that out adding a constructor to the PersonResource and printing something just to know if everytime I do a GET or a POST the constructor prints the line I wrote and it did it so I realized that a separate instance of the servlet is instantiated in each interaction. I also did updated the object Person with the POST and got the information stored with the GET by converting the object in singleton just for testing purposes and having a better understanding
Hi, this is very wonderful tutorial it helped me alot.
Bt i hv 1 doubt. .though m using “id As in LONG Format its returning in STRING format “I m newbie to tis so if anythng i missd correct me pls…
thankyou
The ID value that’s generated from the GCM registration process might look like a long number, but it’s definitely a string. Make sure it’s enclosed in [\"] quote characters.
Hi, I have recently added an API to my android client called RestEasy mobile, do you know how to work with HTTPS in web services? Does JAX-RS allow HTTPS?
this is a very helpful tutorial to know about web serveice….explanation is very good….
Hi! Nice tutorial, thanks!
I just want to mention that you’re missing a slash “/” in the Path annotation of the getSamplePerson method. So that it would be like this: @Path(“/sample”). I had errors because of that missing.
Regards!
Nice catch! I’ll check that out.
Maybe that could be an obvious issue for experienced people, but for those who we are learning isn’t.
BTW, This tutorial helped me a lot. All is working fine. Thanks again!
Hello
Thank you Mark for this great Tutorial.
I’m trying to implement the Post Button. And send data from my android to my web service.
I read your code to see what are the part that concern the Post event, but I don’t see any clicklistner on the bn_post button?
Please Help!!
Take a look at the main.xml layout file, and you’ll see that the bnPost button has an “onClick” property. This property allows a developer to assign a method to respond to an onClick event (of course!).
I put this in my example, but I am ambivalent about using this XML mapping approach. My thought is that a layout XML file is for layouts, and Java code is for – executing java code. Nevertheless, this XML approach is part of the Android spec, and there you have it.
First of all, I really appreciate you effort. This tutorial is terrific !!
I have one problem thought :
The “response” given as a parameter to the OnPostExecute method contains this :
response value is : Apache Tomcat/7.0.12 – Rapport d”erreur Etat HTTP 415 – Unsupported Media Typetype Rapport d”étatmessage Unsupported Media Typedescription Le serveur a refusé cette requête car l’entité de requête est dans un format non supporté par la ressource demandée avec la méthode spécifiée (Unsupported Media Type).Apache Tomcat/7.0.12
I don’t understand why does it contain html. I’m not able to fill my json object in the handleResponse method.
Do u have any idea what the problem might be ??
I’d have to see more of your project’s code and configuration to give you a decent answer. For starters, what is the content of the URL that you are sending to the server? Put a Debug.Log message there, and let’s see what you are actually sending.
Thanks you so much for the feedback !!
Here’s a screenshot of my LogCat :
https://dl.dropbox.com/u/22176885/Error.png
Hi, This is an excellent example for beginners like me.. I tried to follow the guidelines to build an android app that refers to RESTFul web service. As I debug through, HTTPGet returns a success but then I get AsyncTask.class source not found and all other threadpool related errors. How do I fix that?
What you are seeing is probably not really an error. When you are stepping through your code through the debugger, there will be places where Android’s own code will be called. So the debugger is looking for the source code for AsyncTask, but can’t find it.
Two ways to “fix”, or at least work around, the error. If you recognize that the code you are about to step into is a built-in Android class, or a class from a library or jar where you don’t have the source code, step *over* that class instantiation instead. That’s the workaround.
The other way to “fix” this would be to download Google’s Android source code, and you can do this via the Android SDK Manager. For every version of the Android SDK, there is an option to download the source, but note that this will take a little time to download, and will of course take up a good amount of disk space. But once you have the source code for the SDK version you are using in your project, you will not get that “source not found” error, and you’ll be able to step *into* classes like AsyncTask (if you dare!).
Mark
hi !!when i create my android application the class R.java dissapear !!dont know why !!aty first it was built automatically and now i have the problem R cant be resolved to a variable !!can any boby help me plzzz
If your R.java file has disappeared, it is most likely because there is an issue in one of your XML files. If you are using Eclipse, check your project’s RES folder to see if any errors are listed. Most common place would be in a layout file.
Once you find and fix any XML resource errors, Eclipse (and the ADT) will automatically regenerate the required R.java file.
Hi,
Thanks for such a good tutorial. Can you please tell me how to delete from server through client? Actually i want to delete data which i posted on rest service. How can i do that?
Please help!!!
Thanks in advance.
Officially, in addition to GET and POST, the http standard includes a DELETE command. But the truth is, I’ve seen very few services written to respond to a DELETE submission. A more common approach would be to send a POST that would include, as part of the attached set of key-value pairs, a key that could be called “COMMAND” or “OPTION” or “ACTION” or “TASK”, etc. The basic idea is that the web service would look for that key value to find out what action is being requested.
So, one could create a web service that responds to a POST, with a “COMMAND” key that has the value “DELETE”. The other key values (possibly combined with REST URL mapping) would determine what data to delete. And the web service would delete the data that matched the passed values.
Something like that.
Really appreciate the effort. The tutorial is concise and helpful.
Is there any tutorial on how to implement authentication? or at least, could you point me to the right direction?
Since its a RESTful service, it wouldn’t make sense to mantain a session right?
Many thanks.
You ask a great question. A few Google searches should turn up some decent authentication examples, but you gotta read the fine print. Here’s some example source code that might be worth reading through:
https://gist.github.com/webile-android/1117856
From the bottom of my heart, I love you men. I’ve been struggling with this for ages! Thank you so much!
Them’s mighty kind words.
Awesome post! It’s good to find tutorials that go a step further than hello world, less than giving the kitchen sink but just enough to see how things combine to work together. Hope you do more
Very kind words. I’ve been doing mostly iOS work for the past several months, so no Android posts for a while. But I hope to get back to writing again.