Explain how to use Asynctask in Android _android

Source: Internet
Author: User
Tags static class

There are two ways to implement asynchronous task mechanisms in Android, Handler and Asynctask.

Handler mode needs to create a new thread for each task, after the completion of the task through the handler instance to the UI thread to send messages to complete the interface update, this way for the entire process of control is more subtle, but also has disadvantages, such as the relatively bloated code, in the simultaneous execution of multiple tasks, It is not easy to control the thread precisely.

To simplify the operation, Android1.5 provides a tool class android.os.AsyncTask that makes it easier to create asynchronous tasks without the need to write task threads and handler instances to accomplish the same tasks.

Let's look at the definition of Asynctask:

Public abstract class Asynctask<params, Progress, result> { 

Three generic types represent, respectively, the input parameters to start task execution, the progress of background task execution, and the type of background calculation results. In certain situations, not all types are used, and if they are not used, they can be replaced with Java.lang.Void types.

The execution of an asynchronous task typically includes the following steps:

1.execute (Params ... Params), performing an asynchronous task that requires us to call this method in code to trigger the execution of the asynchronous task.

2.onPreExecute (), executed immediately after execute (Params ... Params), is typically used to mark the UI before performing a background task.

3.doInBackground (Params. Params), executed immediately after OnPreExecute (), to perform a more time-consuming operation, which receives the input parameters and returns the result of the calculation. You can call Publishprogress (Progress. Values) during execution to update progress information.

4.onProgressUpdate (Progress ... values), this method is executed to update the progress information directly on the UI component when publishprogress (Progress ... values) is invoked.

5.onPostExecute (Result results), when the background operation ends, the method is invoked, the results are passed as arguments to the method, and the results are displayed directly on the UI component.

When used, there are a few things to be particularly aware of:

1. An instance of an asynchronous task must be created in the UI thread.

2.execute (Params ... Params) method must be called in the UI thread.

3. Do not manually invoke OnPreExecute (), Doinbackground (Params ... Params), onprogressupdate (Progress ... values), OnPostExecute ( Result result) of the several methods.

4. You cannot change the information for a UI component in Doinbackground (Params. Params).

5. A task instance can only be executed once, and if executed the second time it throws an exception.

Next, let's take a look at how to perform asynchronous task operations using Asynctask, and we first build a project that is structured as follows:
The structure is relatively simple, let's look at the Mainactivity.java code first:

Package Com.scott.async; 
Import Java.io.ByteArrayOutputStream; 
 
Import Java.io.InputStream; 
Import org.apache.http.HttpEntity; 
Import Org.apache.http.HttpResponse; 
Import Org.apache.http.HttpStatus; 
Import org.apache.http.client.HttpClient; 
Import Org.apache.http.client.methods.HttpGet; 
 
Import org.apache.http.impl.client.DefaultHttpClient; 
Import android.app.Activity; 
Import Android.os.AsyncTask; 
Import Android.os.Bundle; 
Import Android.util.Log; 
Import Android.view.View; 
Import Android.widget.Button; 
Import Android.widget.ProgressBar; 
 
Import Android.widget.TextView; 
 
  public class Mainactivity extends activity {private static final String TAG = "Async_task"; 
  Private Button Execute; 
  Private Button Cancel; 
  Private ProgressBar ProgressBar; 
 
  Private TextView TextView; 
 
  Private MyTask Mtask; 
    @Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); 
 
    Setcontentview (R.layout.main); ExeCute = (Button) Findviewbyid (R.id.execute); Execute.setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {//Note 
        Every time you need a new instance, the newly created task can only be executed once, otherwise there will be an exception mtask = new MyTask (); 
 
        Mtask.execute ("http://www.baidu.com"); 
        Execute.setenabled (FALSE); 
      Cancel.setenabled (TRUE); 
    } 
    }); 
    Cancel = (Button) Findviewbyid (r.id.cancel); Cancel.setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {//Cancel 
      An executing task, the Oncancelled method will be called Mtask.cancel (true); 
    } 
    }); 
    ProgressBar = (ProgressBar) Findviewbyid (R.id.progress_bar); 
 
  TextView = (TextView) Findviewbyid (R.id.text_view); 
    Private class MyTask extends Asynctask<string, Integer, string> {//onpreexecute method to do some UI action before performing a background task 
      @Override protected void OnPreExecute () {log.i (TAG, "OnPreExecute () called"); Textview.settext ("Loading.").."); 
    } The Doinbackground method performs a background task internally, and you cannot modify the UI @Override protected String doinbackground (String ... params) {Log within this method. 
      I (TAG, "Doinbackground (Params ... Params) called"); 
        try {httpclient client = new Defaulthttpclient (); 
        HttpGet get = new HttpGet (params[0]); 
        HttpResponse response = Client.execute (get); 
          if (Response.getstatusline (). Getstatuscode () = = HTTPSTATUS.SC_OK) {httpentity entity = response.getentity (); 
          InputStream is = Entity.getcontent (); 
          Long total = Entity.getcontentlength (); 
          Bytearrayoutputstream BAOs = new Bytearrayoutputstream (); 
          byte[] buf = new byte[1024]; 
          int count = 0; 
          int length =-1; 
            while (length = Is.read (BUF))!=-1) {baos.write (buf, 0, length); 
            Count = length; Call Publishprogress to advertise progress, and the last Onprogressupdate method will be executed publishprogress ((int) ((Count/(float) total) *100)); 
          To demonstrate progress, hibernate 500 milliseconds thread.sleep (500); 
        Return to New String (Baos.tobytearray (), "gb2312"); 
      The catch (Exception e) {log.e (TAG, E.getmessage ()); 
    return null; 
      The//onprogressupdate method is used to update progress information @Override protected void onprogressupdate (Integer ... progresses) { 
      LOG.I (TAG, "onprogressupdate (Progress ... progresses) called"); 
      Progressbar.setprogress (Progresses[0]); 
    Textview.settext ("Loading ..." + progresses[0] + "%"); The//onpostexecute method is used to update the UI after the background task finishes, displaying the results @Override protected void OnPostExecute (String result) {Lo 
      G.I (TAG, "onpostexecute result) called"); 
 
      Textview.settext (result); 
      Execute.setenabled (TRUE); 
    Cancel.setenabled (FALSE); The//oncancelled method is used to change the UI @Override protected void oncancelled () {log.i (TAG, oncancelled) when canceling a task in execution 
      () called "); Textview.settext ("Cancelled"); 
 
      Progressbar.setprogress (0); 
      Execute.setenabled (TRUE); 
    Cancel.setenabled (FALSE); 
 } 
  } 
}

The

Layout file Main.xml code is as follows:

<?xml version= "1.0" encoding= "Utf-8"?> <linearlayout xmlns:android= "http://schemas.android.com/apk/res/" Android "android:orientation=" vertical "android:layout_width=" fill_parent "android:layout_height=" "Fill_parent" 
  ; <button android:id= "@+id/execute" android:layout_width= fill_parent "android:layout_height=" wrap_content 
    "android:text=" execute "/> <button android:id=" @+id/cancel "android:layout_width=" Fill_parent "  
    android:layout_height= "Wrap_content" android:enabled= "false" android:text= "Cancel"/> <progressbar  
    Android:id= "@+id/progress_bar" android:layout_width= "fill_parent" android:layout_height= "Wrap_content"  
    android:progress= "0" android:max= "style="? Android:attr/progressbarstylehorizontal "/> <ScrollView Android:layout_width= "Fill_parent" android:layout_height= "wrap_content" > <textview android:i D= "@+id/text_view" aNdroid:layout_width= "Fill_parent" android:layout_height= "wrap_content"/> </ScrollView> </linearlay 
 Out>

Because of the need to access the network, we also need to include access to the network in Androidmanifest.xml:

 
 

Let's take a look at the Run-time interface:

The above screenshots are the initial interface, the interface to perform the asynchronous task, the interface after the successful implementation, and the interface after canceling the task. After successful execution, the entire process log is printed as follows:

If we press the Cancel button while performing a task, the log prints as follows:
You can see that the oncancelled () method will be invoked and the OnPostExecute (result result) method will no longer be invoked.

The above introduces the basic application of asynctask, some friends may have doubts, asynctask internal is how to implement it, the process of its implementation and we use handler what is the difference? The answer is: Asynctask is a good encapsulation of thread+handler, and traces of thread and handler can still be seen in Android.os.AsyncTask code. Here is a detailed introduction to the asynctask of the implementation of the principle.

Let's take a look at Asynctask's outline view first:

We can see some of the key steps in the approach, Doinbackground (Params ... Params) is an abstract method that we must override when inheriting Asynctask; OnPreExecute (), Onprogressupdate (Progress. Values), OnPostExecute (result result), oncancelled () These methods are empty, and we can optionally overwrite them when we need them. Publishprogress (Progress ... values) are final-modified, cannot be overridden, can only be invoked, and we generally call this method in Doinbackground (Params ... Params); We can see that there is a status enumeration class and the GetStatus () method, and the Status enumeration class code snippet is as follows:

The initial state 
private volatile status Mstatus = Status.pending; 
 
public enum Status { 
  /** 
   * indicates this task has not been executed yet. 
  */PENDING, 
  /** * indicates that's the task is 
   running. 
  * * RUNNING,/** 
   * indicates that {@link Asynctask#onpostexecute} has finished. 
  */Finished, 
} 
 
/** * Returns The current status of this 
 task. 
 * 
 * @return The current status. 
 * * Public 
final Status GetStatus () {return 
  mstatus; 
} 

As you can see, the initial state of the Asynctask is pending, represents the pending state, the running represents the execution state, the finished represents the end state, and these states are used in many places in the Asynctask life cycle, which is very important.

After you've covered the outline view, and then we'll go from execute (Params. Params) as a portal, and focus on the Asynctask execution process, let's take a look at the code snippet for the Execute (Params ... Params) method:

Public final Asynctask<params, Progress, result> execute (Params ... Params) { 
  if (mstatus!= status.pending) {
   switch (mstatus) { 
      case RUNNING: 
        //If the task is being executed it throws an exception 
        //It is worth mentioning that after the cancel cancel task was invoked, the state has not been RUNNING 
        throw New IllegalStateException ("Cannot execute task:" 
            + "The task is already running."); 
      Case finished: 
        //If the task has been completed then throws an exception 
        throw new IllegalStateException ("Cannot execute task:" 
            + "task has Already been executed " 
            +" (a task can is executed only once) "); 
    } 
 
  Change state to RUNNING 
  mstatus = status.running; 
 
  Call the OnPreExecute method 
  OnPreExecute (); 
 
  Mworker.mparams = params; 
  Sexecutor.execute (mfuture); 
 
  return this; 
} 

Three unfamiliar variables are involved in the code: Mworker, Sexecutor, mfuture, we'll look at them as well:

With regard to Sexecutor, it is an instance of Java.util.concurrent.ThreadPoolExecutor, which is used to manage the execution of threads. The code is as follows:

private static final int core_pool_size = 5; 
private static final int maximum_pool_size = 128; 
private static final int keep_alive = ten; 
 
Create a new queue to store threads 
private static final blockingqueue<runnable> Sworkqueue = 
    new linkedblockingqueue< Runnable> (ten); 
Create a new thread factory 
private static final threadfactory sthreadfactory = new Threadfactory () { 
  private final Atomicinteger Mcount = new Atomicinteger (1); 
  Create a new thread public thread 
  Newthread (Runnable r) {return 
    new thread (R, "Asynctask #" + mcount.getandincrement ()); 
  } 
}; 
Creates a new thread pool executor for managing the execution of threads 
private static final Threadpoolexecutor Sexecutor = new Threadpoolexecutor (core_pool_size , 
    

Mworker is actually an implementation object instance of an abstract inner class of asynctask that implements the call () method in the Callable<result> interface, and the code reads as follows:

private static abstract class Workerrunnable<params, Result> implements callable<result> { 
  params[] Mparams; 

And Mfuture is actually an instance of Java.util.concurrent.FutureTask, and the following is information about its Futuretask class:

/** 
 * A cancellable asynchronous computation. 
 * ... 
 */ 
Public interface runnablefuture<v> extends Runnable, future<v> { 
  /** 
   * Sets of its computation 
   * unless it has been cancelled. 
   * 
  /void run (); 

You can see that Futuretask is a class that can be canceled in the middle of an asynchronous computation.

The following are examples of Mworker and mfuture in Asynctask:

Private final Workerrunnable<params, result> Mworker; 
 
Private final futuretask<result> mfuture; Public Asynctask () {mworker = new workerrunnable<params, result> () {//call method is called, the priority is set to the background level, and then the call to Asynctask Doinbackground method Public result call () throws Exception {process.setthreadpriority (process.thread_priority_ba 
      Ckground); 
    Return Doinbackground (Mparams); 
 
  } 
  }; In the Mfuture instance, Mworker will be invoked to do the background task, which will invoke the Done method mfuture = new Futuretask<result> (mworker) {@Override prote 
      CTED void Do () {message message; 
 
      result result = NULL; 
      try {result = get (); 
      catch (Interruptedexception e) {ANDROID.UTIL.LOG.W (Log_tag, E); 
            catch (Executionexception e) {throw new RuntimeException ("An error occured while executing doinbackground ()", 
      E.getcause ()); catch (Cancellationexception e) {//Send cancellation message = Shandler.obtainmesSage (Message_post_cancel, New Asynctaskresult<result> (Asynctask.this, (result[)) null); 
        Message.sendtotarget (); 
      Return The catch (Throwable t) {throw new RuntimeException ("An error occured while executing" + "doinbackgr 
      Ound () ", t); //Send message = Shandler.obtainmessage (Message_post_result, new Asynctaskresult<resu) showing results 
      Lt> (asynctask.this, result)); 
    Message.sendtotarget (); 
} 
  }; 
 }

We see the above code, in the Mfuture instance object's done () method, if a cancellationexception type exception is caught, a "message_post_cancel" message is sent, and if executed successfully, A "Message_post_result" message is sent, and the message is associated with a Shandler object. This Shandler instance is actually an instance of the Asynctask inner class Internalhandler, and Internalhandler is inheriting handler, so let's analyze its code:

private static final int message_post_result = 0x1;  Display results private static final int message_post_progress = 0x2; Update progress private static final int message_post_cancel = 0x3; 
 
Cancel task private static final Internalhandler Shandler = new Internalhandler (); 
  private static class Internalhandler extends Handler {@SuppressWarnings ({"Unchecked", "Rawuseofparameterizedtype"}) 
    @Override public void Handlemessage (message msg) {Asynctaskresult result = (Asynctaskresult) msg.obj; 
        Switch (msg.what) {case Message_post_result://There be only one result//Call Asynctask.finish method 
        Result.mTask.finish (Result.mdata[0]); 
      Break Case message_post_progress://Call Asynctask.onprogressupdate method Result.mTask.onProgressUpdate (Result.mdata) 
        ; 
      Break 
        Case MESSAGE_POST_CANCEL://Call asynctask.oncancelled method result.mTask.onCancelled (); 
    Break 
 } 
  } 
}

We saw that when we encountered "Message_post_result" when we were dealing with the message, it called the Finish () method in Asynctask, and we looked at the definition of the finish () method:

private void finish (result result) { 
  if (iscancelled ()) result = NULL; 
  OnPostExecute (result); Call OnPostExecute display result 
  mstatus = status.finished;//Change status to Finished 
} 

The original finish () method is responsible for invoking the OnPostExecute (Result results) method to display the outcome and change the status of the task.

In addition, in the Mfuture object's done () method, when constructing a message, the message contains a Asynctaskresult type object, and then in the Shandler instance object's Handlemessage (msg) method, Get the object that came with the message in the following way:

Asynctaskresult result = (Asynctaskresult) msg.obj; 

What is this asynctaskresult, and what does it contain? It is also an internal class of asynctask that is used to wrap a class of execution results, let's take a look at its code structure:

@SuppressWarnings ({"Rawuseofparameterizedtype"}) 
private static class Asynctaskresult<data> { 
  final Asynctask Mtask; 
  Final data[] Mdata; 
 
  Asynctaskresult (asynctask task, data ... data) { 
    mtask = task; 
    Mdata = data; 
  } 
 

Look at this asynctaskresult encapsulates a asynctask instance and some type of dataset, let's look at the code to build the message:

Messages Message 
= Shandler.obtainmessage (message_post_cancel, new asynctaskresult<result>) sent to cancel task 
    ( Asynctask.this, (result[]) (null)); 
Message.sendtotarget (); 
Sends message 
= Shandler.obtainmessage (Message_post_result, new asynctaskresult<result>) that displays the results 
     ( Asynctask.this, result)); 
Message.sendtotarget (); 

How to use this object when processing messages, let's look at it again:

Result.mTask.finish (Result.mdata[0]); 

Generally speaking, when we call the Execute (Params. Params) method, the Execute method invokes the OnPreExecute () method. A futuretask task is then executed by the Threadpoolexecutor instance Sexecutor, in which Doinbackground (Params ... Params) is invoked, If the publishprogress (Progress ... values) method is invoked by the developer-overridden Doinbackground (Params. Params) method, A message_post_progress message is sent through the Internalhandler instance Shandler, and the progress is updated Shandler onprogressupdate (Progress ... values) when processing the message method is invoked, and if an exception is encountered, a MESSAGE_POST_CANCEL message is sent, the task is canceled, shandler the Oncancelled () method is invoked when the message is processed, and if the execution succeeds, send a message_post_ Results, displays the result, Shandler the OnPostExecute method is invoked when the message is processed.

After the introduction, I believe that friends have recognized the essence of asynctask, it thread+handler good encapsulation, reduce the developer to deal with the complexity of the problem, improve the development efficiency, I hope friends can appreciate a lot.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.