Android SDK: Asynchronous HTTP Requests

Let’s make an Android application to send a value that you type in a text box to a server script via HTTP post. We will handle the HTTP request in an asynchronous fashion so that the application does not freeze while the request is happening.

Our application, shown below, will have a text box, a button, and a progress view so that the user knows that the data is been sent.

an android application sending data via http, a progress bar shows the progress

Asynchronous HTTP application: sending data, a progress bar view shows the progress.


After the value is sent a toast message will be displayed as shown below.
the application's state after the http request was performed

message sent state of application

The User Interface

As shown above, it simply consists of a button, progress bar, text box, and label.

res/layout/home_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:text="Enter Something Below:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="30dp"
        android:ems="10"
        android:hint=""
        >

        <requestFocus />
    </EditText>

    <ProgressBar
        android:id="@+id/progressBar1"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/editText1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="24dp" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignRight="@+id/editText1"
        android:layout_below="@+id/progressBar1"
        android:layout_marginTop="24dp"
        android:text="Submit" />

</RelativeLayout>

Linking Layout to Activity

Now let’s link each of our views in the layout to code in java.

	private EditText value;
	private Button btn;
	private ProgressBar pb;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.home_layout);
		value=(EditText)findViewById(R.id.editText1);
		btn=(Button)findViewById(R.id.button1);
		pb=(ProgressBar)findViewById(R.id.progressBar1);
		pb.setVisibility(View.GONE);
		btn.setOnClickListener(this);
	}

Notice that we have turned off the visibility of our prograss, it will become visible only while the data is been sent.

HTTP Posting Data

Let’s say that I want to POST the value from my app to the following PHP script stored in a server at some website.

receiver.php
<?php
 // receive data from app's http request
 $data=$_POST["myHttpData"];
 // write data from my android app to a text file
 file_put_contents('myTextFile.txt',$data);
?>

I can do that very easily from Android using the HttpClient class in a method that I can call with the value I want to send.

public void postData(String valueIWantToSend) {
	HttpClient httpclient = new DefaultHttpClient();
        // specify the URL you want to post to
	HttpPost httppost = new HttpPost("http://somewebsite.com/receiver.php");
	try {
		// create a list to store HTTP variables and their values
		List nameValuePairs = new ArrayList();
                // add an HTTP variable and value pair
		nameValuePairs.add(new BasicNameValuePair("myHttpData", valueIwantToSend));
		httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                // send the variable and value, in other words post, to the URL
		HttpResponse response = httpclient.execute(httppost);
	} catch (ClientProtocolException e) {
		// process execption
	} catch (IOException e) {
		// process execption
	}
}

The first parameter of the BasicNameValuePair constructor is the name of the HTTP variable in the PHP script, the second is the value that will be stored in $data.

If you would like to post more values simply add another name-value pair line.

The Asynchronous Class

If you just call the postData method created above, your application will hang until the whole HTTP process has completed. The correct way to handle this method is to use the AsyncTask class.

We will create a class, inside the activity’s class, that extends the AsyncTask class. The method doInBackground needs to be implemented. Inside of it you put the code that needs to be handled asynchronously. Notice that we access the parameter of this method as an array, the three dots simply mean that we can pass more than one value when it’s called. Since we are only passing one value to it we just have to access the first array element, hence params[0] is used.

private class MyAsyncTask extends AsyncTask<String, Integer, Double>{
  @Override
  protected Double doInBackground(String... params) {
	// TODO Auto-generated method stub
	postData(params[0]);
	return null;
  }
}

We will also add the optional methods onPostExecute and onProgressUpdate to track when the postData method has completed and its progress respectively. When the request has completed we will hide the progress bar and send a message to the user.

private class MyAsyncTask extends AsyncTask<String, Integer, Double>{
  @Override
  protected Double doInBackground(String... params) {
	// TODO Auto-generated method stub
        postData(params[0]);
        return null;
  }

  protected void onPostExecute(Double result){
	pb.setVisibility(View.GONE);
	Toast.makeText(getApplicationContext(), "command sent", Toast.LENGTH_LONG).show();
  } 
  
  protected void onProgressUpdate(Integer... progress){
    pb.setProgress(progress[0]);
  }
}
Note: The values String, Integer, and Double of the AsyncTask class maybe be change to any other type to suit your needs.

When The Button I Clicked

When the user clicks the button we will first check that he/she has entered something, then we will call our custom async class using by creating a anonymous object of it and calling the execute method with the value we want to HTTP post.

public void onClick(View v) {
 // TODO Auto-generated method stub
 if(value.getText().toString().length()<1){
 // out of range
 Toast.makeText(this, "please enter something", Toast.LENGTH_LONG).show();
 }else{
   pb.setVisibility(View.VISIBLE);
  new MyAsyncTask().execute(value.getText().toString());		
 }
} 

Full Code

This is the code for the activity all put together, enjoy.

package com.example.asynchttppost;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.opengl.Visibility;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class Main extends Activity implements OnClickListener{

	private EditText value;
	private Button btn;
	private ProgressBar pb;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.home_layout);
		value=(EditText)findViewById(R.id.editText1);
		btn=(Button)findViewById(R.id.button1);
		pb=(ProgressBar)findViewById(R.id.progressBar1);
		pb.setVisibility(View.GONE);
		btn.setOnClickListener(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.home, menu);
		return true;
	}

	public void onClick(View v) {
		// TODO Auto-generated method stub
			if(value.getText().toString().length()<1){
				
				// out of range
				Toast.makeText(this, "please enter something", Toast.LENGTH_LONG).show();
			}else{
				pb.setVisibility(View.VISIBLE);
				new MyAsyncTask().execute(value.getText().toString());		
			}
		

	} 

	private class MyAsyncTask extends AsyncTask<String, Integer, Double>{

		@Override
		protected Double doInBackground(String... params) {
			// TODO Auto-generated method stub
			postData(params[0]);
			return null;
		}

		protected void onPostExecute(Double result){
			pb.setVisibility(View.GONE);
			Toast.makeText(getApplicationContext(), "command sent", Toast.LENGTH_LONG).show();
		}
		protected void onProgressUpdate(Integer... progress){
			pb.setProgress(progress[0]);
		}

		public void postData(String valueIWantToSend) {
			// Create a new HttpClient and Post Header
			HttpClient httpclient = new DefaultHttpClient();
			HttpPost httppost = new HttpPost("http://somewebsite.com/receiver.php");

			try {
				// Add your data
				List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
				nameValuePairs.add(new BasicNameValuePair("myHttpData", valueIWantToSend));
				httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

				// Execute HTTP Post Request
				HttpResponse response = httpclient.execute(httppost);

			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
			} catch (IOException e) {
				// TODO Auto-generated catch block
			}
		}

	}
}

Related posts: