≡ Menu

How To Use Android AsyncTask for UI Threads with an Example Code

Responding to user’s input as fast as possible is essential for a good user experience.

Android uses an UI thread, which is also the main thread of an app to render UI.

By default, all the functions exposed to the programmer are called by the UI thread.

Android OS guards on the UI thread, and if the app takes too much of time for input or broadcast event, Android Not Responding dialog will shown up, with which user can choose to wait for the app to respond, or close the app.

Time consuming jobs such as big data processing, database or network accessing that run in UI thread may cause an ANR error (application not responding).

Please note that Android forbids the execution of network accessing code in an UI thread.

As shown below, if we try to access a web page with HttpClient, the execution of DefaultHttpClient().execute() will be terminated with a NetworkOnMainThreadException exception.

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  this.findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
       // TODO Auto-generated method stub
       try {
         new DefaultHttpClient().execute(new HttpGet("http://www.google.com"));
       } catch (ClientProtocolException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
       } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
       } catch (NetworkOnMainThreadException e) {
         //Android will reject the network accessing by throwing an exception
         Log.i("E", "Access network on the main/UI thread!!");
       }
    }
  });
}

The best solution to avoid ANR (Application not responding) error is using a worker thread running parallel with UI thread.

Besides the standard java thread, android provides the AsyncTask class for easy thread control.

The following are the four AsyncTask functions that can be used:

  1. onPreExecute – This is called before the execution.
  2. onPostExecute – This is called after the execution.
  3. onProgressUpdate – UI update should only be done in this function. When and how this function will be triggered is defined by the programmer. Need to notice that, even onProgressUpdate can access and update the UI component, as Activity would be killed and recreated on screen rotation case, it not safe to continue the update after that. One common solution is save the state and stop the AsyncTask, then restart the AsyncTask to continue its job.
  4. doInBackground – This is the main working function. If progress update is necessary, the publishProgress can be called, which will finally leads to the calling of onProgressUpdate. This is very important as doInBackground is working on different thread with UI thread, any cross thread accessing is not allowed. isCancelled() can be used to test the state of thread, so as to do the job properly.

The following code is designed to broadcast a dummy package through port 0x4b4b, and put address that responds to the broadcast into a list component.

AsyncTask is a template class which takes three type arguments: the first is the type for argument of doInBackground; the second is the type for the argument of onProgressUpdate; the third is the type for the argument onPostExecute. These three functions each have an input argument of vargars type.

private class GetAddressTask extends AsyncTask<Void, String, Void> {
  @Override
  protected void onProgressUpdate(String... values) {
    // TODO Auto-generated method stub
    if (!isCancelled()) {
      // Display current found address in a TextView
      TextView txt = (TextView) findViewById(R.id.serverTextView);
      String msg = new String();
      msg = String.format("%s%s", getString(R.string.server_found),
               values[0]);
      txt.setText(msg);
      // Append all found address in a listView
      listItems.add(values[0]);
      adapter.notifyDataSetChanged();     
    }
    super.onProgressUpdate(values);
  }

  @Override
  protected Void doInBackground(Void... params) {
    // TODO Auto-generated method stub       
    try {
      DatagramSocket s = new DatagramSocket();
      byte data[] = new byte[256];
      InetAddress broadAddr = InetAddress.getByName(getBroadcast());
      DatagramPacket dp = new DatagramPacket(data, 0, broadAddr, 0x4b4b);
      s.setBroadcast(true);
      s.send(dp);
      s.setSoTimeout(1000);
      while(!isCancelled()) {
        try {
             s.receive(dp);
        } catch (SocketTimeoutException e) {
             continue;
        }
        publishProgress(dp.getAddress().toString().substring(1));            
      }
      s.close();
    } catch (Exception e){
        Log.w("DEBUG", e.getMessage());
    }
    return null;
  }
  @Override
  protected void onPostExecute(Void result) {
    // TODO Auto-generated method stub
    super.onPostExecute(result);
  }

  @Override
  protected void onPreExecute() {
    // TODO Auto-generated method stub
    super.onPreExecute();
  }
  private String getBroadcast() throws SocketException {
    //Get the broadcast address
  }

}
Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book