Explain the usage and source code of the Asynctask class used for threading in Android _android

Source: Internet
Author: User
Tags joins static class

Why do you use Asynctask?
We write the app has a principle, the main thread can not run the need to occupy a large number of CPU time slices of the task, such as a large number of complex floating-point operations, large disk IO operations, network sockets and so on, which will cause our main thread to the user's response to become slow, or even ANR, These will make the user experience of the application worse, but sometimes it is necessary to perform these time-consuming tasks, so we can usually use asynctask or new Thread
To deal with, this puts the task in the worker thread, does not occupy the main thread of the time slice, so the main thread will respond to the user's action in time, if the use of new thread to perform the task, if you need to cancel the task execution or need to return the task execution results, we need to maintain a lot of extra And Asynctask is based on the concurrent package provided by the Concurrency class implementation, the above two requirements have been to help us encapsulate, which is the reason we choose Asynctask.

How to use Asynctask
let's simply introduce some examples of the use of asynctask. We first create a new class demoasynctask inherit Asynctask, because Asynctask is an abstract class where the Doinbackground method must be overridden.

Private class Demoasynctask extends asynctask<string, void, void> {
 @Override
 protected void OnPreExecute () {
  super.onpreexecute ();
 }

 @Override
 protected Void doinbackground (String ... params) {return
  null;
 } 

 @Override
 protected void onpostexecute (void avoid) {
  super.onpostexecute (avoid);
 }

 @Override
 protected void onprogressupdate (void ... values) {
  super.onprogressupdate (values);
 }

 @Override
 protected void oncancelled (void avoid) {
  super.oncancelled (avoid);
 }

 @Override
 protected void oncancelled () {
  super.oncancelled ();
 }
}

Demoasynctask task = new Demoasynctask ();
Task.execute ("Demo Test Asynctask");
Task.executeonexecutor (asynctask.serial_executor, "test");
Mytask.executeonexecutor (asynctask.thread_pool_executor, "test");

Under Simple analysis
above is the simplest use of asynctask, the method that we rewrite above, the Oninbackground method runs on the worker thread, the other methods all run in the main thread, and its running mode Android provides us with 2 methods, which are listed above.

1. The first method will use the default EXECUTOR to perform our task, in fact, that is, serial_executor,serial_executor we can also be customized by way of, Android to help our default implementation is to perform the task, That is, single-threaded, the task of asynctask is single-threaded implementation or multi-threaded implementation there is a very interesting history, the earlier version is a single-threaded implementation, Starting from android2.x, Google changed it to multithreading, then Google found that multi-threaded implementation, there will be many need to ensure thread safety extra work for developers, so starting from Android3.0, and the default implementation to single-threaded, today we are demonstrating the Framwork code version Ben is (Android5.0).
2. At the same time also provides a multithreaded implementation of the interface, that we write the last line of code asynctask.thread_pool_executor.

Public final Asynctask<params, Progress, result> execute (Params ... Params) {return
 executeonexecutor ( Sdefaultexecutor, params);
private static volatile Executor sdefaultexecutor = Serial_executor;

In fact, I believe that we often work in learning to use asynctask, we go directly to see Asynctask class source code (insert a digression, usually we can also work on their own learning experience summed up, note to ~ ~)

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

Asynctask abstract class, there are three generic parameter types, the first one is the type of parameter you need to pass in, the second is the type of task completion progress is generally integer, the third is the return type of the task completion result, sometimes these parameters are not all need, not need to set to void, In addition, result is only one, but params can have multiple.
We can see that the default constructor for Asynctask initializes two objects, Mworker and Mfuture.

Private final Workerrunnable<params, result> Mworker;
Private final futuretask<result> mfuture;
 Mworker = new Workerrunnable<params, result> () {Public result call
  () throws Exception {
   Mtaskinvoked.set ( true);

   Process.setthreadpriority (process.thread_priority_background);
   Noinspection unchecked return
   postresult (Doinbackground (Mparams));
  }
 ;

 Mfuture = new Futuretask<result> (mworker) {
  @Override
  protected void Done () {
   try {
    Postresultifnotinvoked (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 ());
   Cancellationexception e) {
    postresultifnotinvoked (null);}}
 ;

Mwoker implements the callback interface, the callback interface is an interface in the advanced concurrency package that JDK1.5 joins, and it can have a generic return value.

Public interface Callable<v> {
/**
 * Computes-a result, or throws a exception if unable to does so.
 *
 * @return computed result
 * @throws Exception if unable to compute a result
 *
/V call () throws Exception ;
}

Futuretask implementation of the Runnablefuture interface, Runnablefuture interface is provided by the JDK, see the name to know it inherits the runnable and future interface, Mfuture is an example of Futuretask, Can be directly execute by the Executor class instance. Let's keep looking at Asynctask's Execute method.

 public final asynctask<params, Progress, result> execute (Params ... Params) {RET
Urn Executeonexecutor (sdefaultexecutor, params); Public final Asynctask<params, Progress, result> executeonexecutor (Executor exec, Params ... Params) {if (mstat
      US!= status.pending) {switch (mstatus) {case Running:throw new IllegalStateException ("Cannot Execute task:"
   + "The task is already running.");
      Case Finished:throw New IllegalStateException ("Cannot execute task:" + "task has already been executed"
  + "(a task can be executed only once)");

 } mstatus = status.running;

 OnPreExecute ();
 Mworker.mparams = params;

 Exec.execute (mfuture);
return this; }

The

invokes the OnPreExecute () method, which is still in the main thread (strictly speaking, the asynctask execution), and then Exec.execute (Mfuture), handing the task to exec processing, execute Mfuture is actually invoke Mwoker, and then call Postresult (Doinbackground (Mparams)), which is already running on the worker thread pool and does not block the main thread. Then send Message_post_result message to Mhandler, then call finish method, if iscancelled, callback oncancelled, otherwise callback onpostexecute.

 private result Postresult (result result) {@SuppressWarnings (' unchecked ') message mess
 Age = Shandler.obtainmessage (the Message_post_result, new asynctaskresult<result> (this, result));
 Message.sendtotarget ();
return result;
private static final Internalhandler Shandler = new Internalhandler (); private static class Internalhandler extends Handler {@SuppressWarnings ({"Unchecked", "Rawuseofparameterizedtype"}) @O
  Verride public void Handlemessage (message msg) {Asynctaskresult result = (Asynctaskresult) msg.obj; 
    Switch (msg.what) {case Message_post_result://There be only one result Result.mTask.finish (result.mdata[0));
   Break
    Case MESSAGE_POST_PROGRESS:result.mTask.onProgressUpdate (Result.mdata);
  Break
 }} private void finish (result result) {if (iscancelled ()) {oncancelled (result);
 else {OnPostExecute (result);
} mstatus = status.finished; }

Now we've actually gone through the process of asynctask the entire mission, and the few callback methods we've exposed have come up. Now that we look back, Asynctask is just an advanced concurrency feature for JDK 1.5, an encapsulation of the concurrent package that makes it easier for developers to handle asynchronous tasks, and of course there's a lot of detail to be learned, such as feedback on task execution progress, The task of enforcing atomicity guarantees and so on, these leave everybody to learn by themselves.

SOURCE Analysis
below we go deeper some, see Asynctask source code. Below is an analysis of the implementation of this class, the main wired pool, and the handler two parts.

Thread pool
when a asynctask is executed, the Execute () method is invoked, starting at this point:

Public final Asynctask<params, Progress, result> execute (Params ... Params) {return
 executeonexecutor ( Sdefaultexecutor, params);
Public final Asynctask<params, Progress, result> executeonexecutor (Executor exec, 
  Params ... Params) { 
 if (Mstatus!= status.pending) { 
  switch (mstatus) {case 
   RUNNING: 
    throw new IllegalStateException ("Cannot execute task:" + "the task is Alre Ady running. "); 
       
   Case finished: 
    throw new IllegalStateException ("Cannot execute task:" + "the task has already been executed" + "(A Task can be executed only once) " 
      
      
  } 
 } 
 
 Mstatus = status.running; 
 Execute OnPreExecute
 onpreexecute () first; 
 
 Mworker.mparams = params; 
 
 Exec.execute (mfuture); 
 return this; 
} 

The Execute method invokes Executeonexecutor. In this method, first check whether the task has been executed or finished, and then mark the task as running. The first thing to do is OnPreExecute, and then assign the parameter to the Mworker object. This mworker is a callable object that is eventually packaged as a futuretask and the code is as follows:

 private static abstract class Workerrunnable<params, result> implements callable& Lt 
result> {params[] mparams; Mworker = new Workerrunnable<params, result> () {public result call () throws Exception {Mtaskinvoked.set 

   (true); 
   Process.setthreadpriority (Process.thread_priority_background); 
  Noinspection unchecked return Postresult (Doinbackground (mparams));
 
} 
 }; Mfuture = new Futuretask<result> (mworker) {@Override protected void done () {try {Postresultifnotinvoke 
  D (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) {postresultifnotinvoked (null); 

} 
 } 
}; 


As you can see from the code above, the call () method in the Mworker object calls Doinbackground, and the return value is given to the Postresult method, which sends a message through handler, which is later analyzed in detail.

After the Mworker object is encapsulated as Futuretask, it is executed by the thread pool, as can be seen from the Execute method, using Sdefaultexecutor, whose value defaults to Serial_executor, which is the serial executor, which is implemented as follows:

 private static class Serialexecutor implements Executor {//Linear bidirectional queue to store all asynctask tasks 
 Final arraydeque<runnable> mtasks = new arraydeque<runnable> (); 

 The Asynctask task currently being performed Runnable mactive; Public synchronized void Execute (final Runnable R) {//Add a new Asynctask task to the bidirectional queue Mtasks.offer (new Runnable () {Publ 
    IC void Run () {try {///Execute Asynctask Task R.run (); 
    finally {///Current task execution completes next task Schedulenext (); 
  } 
   } 
  }); 
  if (mactive = = null) {Schedulenext ();  } protected synchronized void Schedulenext () {//takes the task of the queue header from the task queue and, if so, to the concurrent thread pool to execute if ((mactive = Mtasks.poll ()) 
  != null) {Thread_pool_executor.execute (mactive);  }} public static final Executor thread_pool_executor = new Threadpoolexecutor (core_pool_size, Maximum_pool_size, 

Keep_alive, Timeunit.seconds, Spoolworkqueue, sthreadfactory); 

In the above code, if a task executes, the Serialexecutor Execute method is invoked, and its logic is to add the Runnable object to the Arraydeque queue and then determine if the Mactivie is empty. The first execution of mactive of course is empty, so the execution of Schedulenext, in fact, is to take out the first task in the queue of tasks to the thread pool (thread_pool_executor) execution. The Run method of the Runnable object that joins the Mtask queue will eventually call Schedulenext, and then the team head task will be taken out of the task queue. This enables single-threaded sequential execution, so the default enabled in Asynctask is single-threaded execution, which performs the next task only after the last task executes. If you want to enable multithreading to perform tasks, you can call Executeonexecutor (Executor exec, Params ... Params) directly, where the Executor parameter can be used asynctask the band Thread_pool_ EXECUTOR, you can also define your own.

Handler
Asynctask internally uses handler to deliver the message, which is implemented as follows:

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 
    result.mTask.finish ( Result.mdata[0]); 
    break; 
   Case message_post_progress: 
    result.mTask.onProgressUpdate (result.mdata); 
    break; 
  }}} 
 

If the message type is a return value (Message_post_result) after the task executes, the finish () method is called:

private void finish (result result) { 
 if (iscancelled ()) { 
  oncancelled (result); 
 } else { 
  OnPostExecute (result); 
 } 
 Mstatus = status.finished; 
} 

As you can see from the above, if the task is canceled, call oncancelled, otherwise call OnPostExecute, so if a asynctask task is canceled, then OnPostExecute will not be executed.

If the message type is execution Progress (message_post_progress) will call Onprogressupdate, the method defaults to a null method, which we can rewrite according to our own needs.

Summarize
The main logic of Asynctask, as analyzed above, sums up a few points to note:

    • Asynctask classes must be Cheng in the UI line (the system will help us automate the start of 4.1)
    • The Asynctask object must be created on the UI thread
    • The Execute method must be invoked on the UI thread
    • Do not manually invoke OnPreExecute (), Doinbackground, Onprogressupdate methods
    • A task can only be invoked once (the second call throws an exception)
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.