//
you're reading...
Android, Threads

AsyncTask: Calling web services in background thread

While programming on the android, it is important to remember that lengthy operations that may take more than 20ms are to be avoided on the main UI thread. A UI thread is the main thread in which all of your activities run. Operations that take more than 20ms cause your application’s UI to appear sluggish and unresponsive. Sometimes, you android system may mark you application as unresponsive and display the infamous “Application is not responding” dialog. This cannot be good for your application.

The trick here is to perform all such operations in a background thread. Fortunately, android api’s provide a very useful class that you can subclass according to your needs for performing such operations without creating runnable and thread classes. This is the AsyncTask class. Please refer to the android SDK reference for documentation of the AsyncTask class.

Below I reproduce a helper subclass I wrote specifically for invoking web services in a background thread.


public class AsyncInvokeURLTask extends AsyncTask<Void, Void, String> {
    private final String                 mNoteItWebUrl = "your-url.com";
    private ArrayList<NameValuePair>     mParams;
    private OnPostExecuteListener        mPostExecuteListener = null;

    public static interface OnPostExecuteListener{
        void onPostExecute(String result);
    }

    AsyncInvokeURLTask(
        ArrayList<NameValuePair> nameValuePairs,
        OnPostExecuteListener postExecuteListener) throws Exception {

        mParams = nameValuePairs;
        mPostExecuteListener = postExecuteListener;
        if (mPostExecuteListener == null)
            throw new Exception("Param cannot be null.");
    }

    @Override
    protected String doInBackground(Void... params) {

        String result = "";

        // Create a new HttpClient and Post Header
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(mNoteItWebUrl);

        try {
            // Add parameters
            httppost.setEntity(new UrlEncodedFormEntity(mParams));

            // Execute HTTP Post Request
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            if (entity != null){
                InputStream inStream = entity.getContent();
                result = convertStreamToString(inStream);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        if (mPostExecuteListener != null){
            try {
                JSONObject json = new JSONObject(result);
                mPostExecuteListener.onPostExecute(json);
            } catch (JSONException e){
                e.printStackTrace();
            }
        }
    }

    private static String convertStreamToString(InputStream is){
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;

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

The argument ArrayList<NameValuePair> to the class’s constructor is used to pass name value pairs to the invoked service. You can use this class as follows:

ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("command", "do_get_shop_list"));
nameValuePairs.add(new BasicNameValuePair("arg1", String.valueOf(getUserID())));

AsyncInvokeURLTask task = new AsyncInvokeURLTask(
    nameValuePairs,
    new AsyncInvokeURLTask.OnPostExecuteListener {
        public void onPostExecute(String result) {
            // Do here whatever you want to do when the task completes.
            // The data returned by the invoked service will be contained
            // in the result argument
        }
    };
task.execute();

Discussion

6 thoughts on “AsyncTask: Calling web services in background thread

  1. hey hi,
    will this code work if my mNoteItWebUrl starts with ftp://mydomain.

    Posted by karthik | April 29, 2012, 12:24 pm
  2. I don’t think so. This code uses HttpClient, HttpPost and HttpResponse objects which are specifically meant for the http POST method. I’m sorry I’m not aware of how to use ftp.

    Posted by coredumb | May 1, 2012, 9:52 am
  3. There are 2 bugs in this example, the first one is in the json on part number 1 line 56.

    error: method onPostExecute in interface OnPostExecuteListener cannot be applied to given types;
    mPostExecuteListener.onPostExecute(json);
    required: String
    found: JSONObject
    reason: actual argument JSONObject cannot be converted to String by method invocation conversion

    The other one is in the part number 2 on line 07 where it complains about a missing ( or {.

    I cant seem to fix neither of them. Help would be usefull.

    Posted by Cesar Araujo | December 19, 2012, 4:23 pm
  4. Tried this, but when I put the last block of code to make a call, I get a compile error:
    “The constructor AsyncInvokeURLTask(ArrayList, new onPostExecute(){}) is undefined”

    Any help?

    Posted by ckl_88 | February 14, 2013, 10:12 pm
  5. Hi. This code is very helpful; though as stated in an answer on Stackoverflow.com (http://stackoverflow.com/a/3291713/1635441), the postExecute method is being called on the UI thread, so if the task is a long one, it will possible cause the applcation to crash.

    Posted by ramizmoh | June 13, 2013, 1:32 pm

Leave a comment