Android Core

Android Apache HTTP Client

In this post I want to describe how to build an HTTP client using Apache library. In one of my post I describe how we can use HttpUrlConnection to create a client. Using Apache library I want to explain how we can make POST request, download images and upload multipart binary data. Moreover I will describe how to exchange cookies. So the topics covered are:

  • POST request
  • download binary data
  • upload binary data
  • exchange cookie

 
Apache library is an external library shipped with Android SDK that simplifies the task of making HTTP request.

POST Request

As we know already POST and GET are the basic method that we can use to exchange data with a remote server.As example I will send to a remote server some data in text format (by now). So the first step is creating a DefaultHttpClient that is used a wrapper to send data.

HttpClient client = new DefaultHttpClient();

Once we have our client we have to instantiate a class that handles POST request:

HttpPost post = new HttpPost(url);

where url is the url we want to invoke. To send data we simply have to create a list of
NameValuePair a simple class that holds the name and the value of our parameters we want to send.

List<NameValuePair> nvList = new ArrayList<NameValuePair>();
BasicNameValuePair bnvp = new BasicNameValuePair("name", name);
// We can add more
nvList.add(bnvp);

In this case at line 2 we set the name of the parameter as name and we add the bnvp to the list as said before. Now we have build our list and set it inside our post request so that it can be sent:

post.setEntity(new UrlEncodedFormEntity(nvList));

In this case we encode our parameters using Url encoding. The last step is executing the request through our DefaultHttpClient instance. As a result we obtain an HttpResponse that can be used to read the result of our request:

HttpResponse resp = client.execute(post);

To read the response we can obtain an InputStream (line 1) and consume it reading data in this way:

InputStream is  = resp.getEntity().getContent();            
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder str = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null){
    str.append(line + "\n");
}
is.close();
buffer.append(str.toString());

At the end we have a string that we can use to update our UI.

We have to remember that this operation can be time consuming so that we have to execute this request in an AsyncTask. For more information read the post ‘Android HTTP Client: GET, POST, Download, Upload, Multipart Request’.It is enough to say that all we have done by now should be inside the doInBackground method. Running the example we have:

Server sideandroid_http_apache_client_server

Download binary data

Another common operation is downloading binary data from sever. In this case we want to download an image from the server and show it in our UI.

The operation is very simple because in this case we have to make an HTTP Post request, passing the image name (line 7-10) and read the binary response (line 15-28):

@Override
protected byte[] doInBackground(String... params) {
    String url = params[0];
    String name = params[1];

    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(url);
    List<NameValuePair> paramList = new ArrayList<NameValuePair>();
    paramList.add(new BasicNameValuePair("name", name));
    byte[] data = null;

    try {
        post.setEntity(new UrlEncodedFormEntity(paramList));
        HttpResponse resp = client.execute(post);
        InputStream is = resp.getEntity().getContent();
        int contentSize = (int) resp.getEntity().getContentLength();
        System.out.println("Content size ["+contentSize+"]");
        BufferedInputStream bis = new BufferedInputStream(is, 512);

        data = new byte[contentSize];
        int bytesRead = 0;
        int offset = 0;

        while (bytesRead != -1 && offset < contentSize) {
            bytesRead = bis.read(data, offset, contentSize - offset);
            offset += bytesRead;
        } 
    }
    catch(Throwable t) {
        // Handle error here
        t.printStackTrace();
    }

    return data;
}

At line 17 we read the response length so that we can create a byte array with the same size (see line 21), then at line 19 we create a buffered input stream to read the response stream. Then we simply read the response filling the data byte array. As result we have:

Upload binary data

This is one of most interesting aspect. To handle this operation we need to add an external library to simplify the task. This is a drawback of using apache http client respect to the android native api. On the other side as we saw android native api doesn’t handle multipart request so we have to do everything from zero. Using this library we can simplify the process but we have as a consequence a bigger apk at the end. The library is open source and it is called httpmime-xxx.jar. You can download it here. Remember to add it to your project and has to be exported (see Order and Export in Eclipse). As example we create a multipart request containing some text data and an image. So we start creating always our DefaultHttpClient and HttpPost:

HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);

Now we have to create our post content, called Entity:

MultipartEntity multiPart = new MultipartEntity();

and then add the single parts: two are text data and one is the binary data (the image we want to upload):

multiPart.addPart("param1", new StringBody(param1));
multiPart.addPart("param2", new StringBody(param2));
multiPart.addPart("file", new ByteArrayBody(baos.toByteArray(), "logo.png"));

Notice at line 3 we create a part using a ByteArrayBody to contain the binary data. The we fill the post content with the data we created:

post.setEntity(multiPart);

and then we simply send (or post) it to the server:

client.execute(post);

Running the app we have:

android_http_apache_client_uploadServer sideandroid_http_apache_client_upload_server

Exchange Cookie

One interesting aspect in HTTP protocol is the cookie management. As we know HTTP is a stateless protocol so using cookies we can persist some information across HTTP requests. As example we can suppose to make two HTTP request: one where we invoke a URL and the server returns a cookie containing some information and another one where we send back to the server the cookie.

The first request is very simple:

HttpPost post = new HttpPost(url);
HttpResponse resp = client.execute(post);

Then we read the cookie (line 1,3):

CookieStore store = ((DefaultHttpClient) client).getCookieStore();

List<Cookie> cookies = store.getCookies();
if (cookies != null) {
    for (Cookie c : cookies) { 
        System.out.println("Name ["+c.getName()+"] - Val ["+c.getValue()+"] 
                      - Domain ["+c.getDomain()+"] - Path ["+c.getPath()+"]");
        store.addCookie(c);
    }
}

At line 1 we simply get the cookie store where the cookies are stored. At line 3 we retrieves the cookies list. In the second post request we have to maintain the cookie we retrieved in the first request so we have:

HttpContext ctx = new BasicHttpContext();
ctx.setAttribute(ClientContext.COOKIE_STORE, store);

// Post again with cookie 
HttpPost post1 = new HttpPost(url);
client.execute(post1);
HttpResponse resp1 = client.execute(post, ctx);

At line 1 we create BasicHttpContext to handle cookies and at line 2 we set the store inside our context and finally at line 7 we execute the request passing the context too.

One thing we have to notice is that the DefaultHttpClient is always the same so that we can re-use the cookies.

Running the example we have:

android_http_apache_client_cookie



android_http_apache_client_server_cookie
Client side cookie output Server side cookie output

 
 
Source code available at github.
 

Reference: Android Apache HTTP Client from our JCG partner Francesco Azzola at the Surviving w/ Android blog.

Francesco Azzola

He's a senior software engineer with more than 15 yrs old experience in JEE architecture. He's SCEA certified (Sun Certified Enterprise Architect), SCWCD, SCJP. He is an android enthusiast and he has worked for long time in the mobile development field.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
dragao
dragao
10 years ago

nice post

Ganesh
Ganesh
9 years ago

Really it is very useful post..Here in the last example if you post that servlet(CookieServlet) also,it’ll be helpful for us..Thank you..

Julian
Julian
9 years ago

What if the DefaultHttpClient is not same. I am using POST method & getting the cookies in one activity(loginActivity) and i want to pass it to all other activity to keep the login session active throught my app? Appreciate your work and thanks for the post.

Francesco Azzola
9 years ago
Reply to  Julian

Can’t you have a class that spans across the Activity that handles the Http connections?
It would be better so that you can re-use the code.

Julian
Julian
9 years ago

Thanks Francesco, i just did that. i was confused with, what way i should implement it. looking forward to learn more.

Back to top button