Android's Asynctask is more lightweight than handler and is used for simple asynchronous processing.
Advantages of Use:
L Simple, fast
L Process controllable
Disadvantages of using :
L becomes complex when multiple asynchronous operations are used and UI changes are required.
Asynctask defines three types of generic type params,progress and result. (can also be specified as empty, such as Asynctask <void, Void, void>)
- The Params input parameter that initiates the task execution.
- Progress the percentage of background task execution.
- Results that the result background performs the final return of the task.
A minimum of one asynchronous loading of data is to override the following two methods:
- Doinbackground (Params ...) is performed in the background, and more time-consuming operations can be placed here. This method executes in the background thread, completing the main work of the task. You can call Publishprogress (Progress ...) during execution. To update the progress of the task. Its parameters correspond to the first parameter of Asynctask,publishprogress (Progress ...). The parameter corresponds to the second parameter of Asynctask, and its return value corresponds to the third parameter of Asynctask.
- OnPostExecute (Result) is equivalent to the way handler handles the UI, where it is possible to use the results of the return operation UI that was obtained in Doinbackground. This method executes on the main thread, the result of the task execution (the return value of Doinbackground ) as a parameter of this method.
Of course, you can also rewrite the following three methods, but not required:
- < Span style= "font-size:14px" >onprogressupdate (Progress ...) can use the progress bar to increase user experience. This method executes on the main thread and is used to show the progress of the task execution.
- onpreexecute () Call the Excute () method when the task executes before it starts calling this method.
- oncancelled () user call Cancel (called cancel (True)
Using the Asynctask class, here are a few guidelines to follow:
1. The instance of the task must be created in the UI thread;
2. The Execute method must be called in the UI thread;
3, do not manually call OnPreExecute (), OnPostExecute (Result), Doinbackground (Params ...), Onprogressupdate (Progress ...) These several methods;
4, the task can only be executed once, multiple calls will be an exception;
The order of execution is: OnPreExecute (),doinbackground (),onprogressupdate (),OnPostExecute (). oncancelled () is not necessarily executed.
Except that Doinbackground is executed on a child thread, the rest is performed on the UI thread.
Here's how we use it specifically:
The first step is to create an instance of an asynchronous task and execute it, and the parameters passed in here correspond to the first parameter of Asynctask:
MyTask Mtask = new MyTask (); Mtask.execute (URL);
The second step is to create a class for the asynchronous task, as follows:
Private class MyTask extends Asynctask<string, Integer, string> {//onpreexecute method is used to do some UI action before performing a background task @Override prot ected void OnPreExecute () {Textview.settext ("Start loading ..."); The//doinbackground method performs background tasks internally and cannot modify the UI within this method. The parameters passed in here correspond to the first parameter of Asynctask, the Execute () function passed over the @override protected string Doinbackground (String ... params) {...// Do some time-consuming action publishprogress (progresses); The progresses corresponds to the second parameter of the Asynctask and is also the parameter to be passed to Onprogressupdate (). return result; The return value corresponds to the third parameter of Asynctask, and is also the parameter to pass to OnPostExecute ()}//onprogressupdate method for updating progress information @Override protected void Onprogressupdate (Integer ... progresses) {Textview.settext ("Loading ..." + progresses[0] + "%"); The//onpostexecute method is used to update the UI after performing a background task, displaying the result @Override protected void OnPostExecute (String result) {Textview.settext (Resul T); The//oncancelled method is used to change the UI when canceling a task in execution @Override protected void oncancelled () {Textview.settext ("cancelled");} }The third step, not required, can be called if the task needs to be canceled:
Mtask.cancle (TRUE);
once called, the function does not execute to OnPostExecute (), but instead executes the oncancelled () method.
How is this simple and powerful function implemented? We followed the source to explore. Let's take a look at the Asynctask's build function:
Public Asynctask () { mworker = new Workerrunnable<params, result> () {public Result call () throws Exception { Mtaskinvoked.set (true); Process.setthreadpriority (process.thread_priority_background); Return Postresult (Doinbackground (Mparams)); } ; Mfuture = new Futuretask<result> (mworker) { @Override protected void Done () { ...} }; }
is the establishment of the workerrunnable and Futuretask two instances, and the mworker passed to the mfuture.
We want to start a task will execute the next execute () method, look at its source code, as follows:
Public final Asynctask<params, Progress, result> execute (params ... params) { return Executeonexecutor ( Sdefaultexecutor, params); }
call the Executeonexecutor and continue to see the implementation:
Public final Asynctask<params, Progress, result> executeonexecutor (Executor exec, params ... params) { ... Mstatus = status.running; OnPreExecute (); Mworker.mparams = params; Exec.execute (mfuture); return this; }
here we see the OnPreExecute (), so we can see that OnPreExecute () is executed first, and then called Exec.execute (), from the code above we see that exec is Sdefaultexecutor, So what is Sdefaultexecutor? We see the following code:
public static final Executor serial_executor = new Serialexecutor (); ... private static volatile Executor sdefaultexecutor = Serial_executor;
That is what we actually call the Execute () method of Serialexecutor, to see the implementation:
private Static Class Serialexecutor implements Executor {final arraydeque<runnable> mtasks = new Arraydeque<runnabl E> (); Runnable mactive; Public synchronized void Execute (final Runnable R) {Mtasks.offer (new Runnable () {public void run () {try {r.run (); } finally {Schedulenext (); } } }); if (mactive = = null) {Schedulenext (); }} protected synchronized void Schedulenext () {if ((mactive = Mtasks.poll ()) = null) { Thread_pool_executor.execute (mactive); } } }
First put the task into the Mtasks set, and then determine if Mactivie is empty, call the Schedulenext () method.
Mactivie NULL means that there is currently no task in execution, if mactivie!=null, then the current task is executing, so long as the task is added to the mtasks inside.
Because the Schedulenext () method is called again after the execution of the task is completed,
finally {
Schedulenext ();
}
This form a chain call structure, as long as the mtasks inside there are tasks, will continue to call each other, if there are tasks in the back, just add to mtasks inside can.
The arguments passed to execute () are mfuture, so the run () method is executed to Mfuture, and the Run () method will eventually invoke the following method:
void Innerrun () { if (!compareandsetstate (Ready, RUNNING)) return; Runner = Thread.CurrentThread (); if (getState () = = RUNNING) {//Recheck after setting thread V result; try { result = Callable.call (); } catch (Throwable ex) { setexception (ex); return; } Set (result); } else { releaseshared (0);//Cancel } }
We see a call to Callable.call (), and callable is Mworker, so here's the function:
Public Result Call () throws Exception { Mtaskinvoked.set (true); Process.setthreadpriority (process.thread_priority_background); Return Postresult (Doinbackground (Mparams)); }
Postresult (Doinbackground (mparams)) This sentence went to the Doinbackground () method, and its return value to the Postresult, then we look at the concrete implementation of Postresult!
Private result Postresult (result result) { message message = Shandler.obtainmessage (Message_post_result, new Asynctaskresult<result> (this, Result)); Message.sendtotarget (); return result; }
The original is to use the Shandler to send messages, then we look at the location of processing messages:
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: result.mTask.finish (result.mdata[0]); break; Case message_post_progress: result.mTask.onProgressUpdate (result.mdata); Break;}}}
receive message_post_result on execution finish (), Receive message_post_progress on Execution onprogressupdate (). Let's look at the implementation of the Finish ():
private void finish (result result) { if (iscancelled ()) { oncancelled (result); } else { OnPostExecute ( result); } Mstatus = status.finished; }
here is a decision to invoke a different method depending on whether the task is canceled.
When was the message_post_progress message sent? Guess, it must be in the publishprogress (), to see the realization:
Protected final void publishprogress (Progress ... values) { if (!iscancelled ()) { Shandler.obtainmessage ( Message_post_progress, New asynctaskresult<progress> (this, values)). Sendtotarget (); } }
At this point asynctask related to the process is almost, you can see Asynctask task execution is single-threaded, about Asynctask task execution is a single-threaded implementation or multi-threaded implementation has undergone a change, the earlier version is a single-threaded implementation, From the beginning of the android2.x, Google changed it to multi-threaded implementation, and later found that multi-threaded implementation, there will be a lot of extra work to ensure that thread safety to the developer, so from the Android3.0, and then the default implementation to a single-threaded.
Using multi-threaded implementation, there is a big flaw, that is, the total size of the thread pool is 128, that is, if the number of tasks exceeds 128, then the program will crash, if interested can see my next article "Android asynctask two thread pool analysis and summary."
The use and principle analysis of Asynctask