Android developers should have used Asynctask, through the inheritance Asynctask class to implement asynchronous operations, feedback the current asynchronous execution of the progress, the final results of the implementation of feedback to the UI main thread. We use Asynctask in development because its main advantages are easy to use, no relationship and the main thread interaction logic and execution process controllable, and of course can support cancellation. After saying the Asynctask, we will count the asynctask of the sins below.
1. Different version implementation of concurrency support, need to control the situation of the thread task is difficult to control, when our development requires two tasks must have sequential order, we Android2.3 version asynctask default is concurrent execution, can not control the implementation of the order.
2. The UI cannot be updated outside the main thread;
3. It is not flexible to control the sequence of tasks between threads, for example, when I have multiple tasks task1,task2,task3 and so on, our Task2 and Task3 must wait for Task1 to run first, and our Task2 and TASK3 can run at the same time. At this time Asynctask is difficult to control.
4. Not fully capture the Asynctask Run-time exception.
5.AsyncTask difficult to deal with multitasking UI interaction issues.
We know the shortcomings of asynctask, so that we can have in the future development of the choice of when to use Asynctask, when not to use.
In order to strengthen the understanding of this class of asynctask, I try my best to realize the function of Asynctask, and try to solve the problem of asynctask class of system. We know that the implementation of Asynctask is to encapsulate the implementation of the handler + thread mode to update the UI, and here we will implement our Asynctask implementation First edition (V1.0):
Public abstract class Myasynctask<result> {private static final int core_pool_size = 5;
private static final int message_post_result = 0x1;
Here we create a new default core_pool_size size thread pool public static Executor Executor = Executors.newfixedthreadpool (core_pool_size);
Protected final Internalhandler Shandler = new Internalhandler (); Private result Postresult {message message = Shandler.obtainmessage (Message_post_result, New safeasyncta
Skresult<result> (This,result)); Message.sendtotarget ();
Task execution completes, messages are sent to the UI thread, and our message parameters are encapsulated into the object of the Safeasynctaskresult<result> class.
The public void execute () {Executor.execute futuretask<result> (new callable<result> () {@Override
Public result called () throws Exception {return Postresult (Doinbackground ());//Here is asynchronous task Execution}});
/* * Implement this method, where the true asynchronous task executes/protected abstract result doinbackground (); private static class Internalhandler<result> extends Handler {pubLIC void Handlemessage (msg) {safeasynctaskresult<result> result = (safeasynctaskresult<result>) m
Sg.obj; Switch (msg.what) {case MESSAGE_POST_RESULT:result.mTask.finish (result.mdata);//Note
Here we deal with the Message_post_result in the hander (which indicates the execution of the task) break;
}} private void finish (result result) {OnPostExecute (result);
* * * Task finishes updating UI/protected abstract void OnPostExecute (result result);
private Static class Safeasynctaskresult<data> {final Myasynctask mtask;
Final Data Mdata;
Safeasynctaskresult (myasynctask<?> task, data data) {mtask = task;
Mdata = data;
}
}
}
We look at our V1.0 implementation, which basically implements an asynchronous threading operation in handler + thread mode. But there are a lot of problems, first of all have not implemented basic cancellation function, then, we can not do the thread execution order, also do not have to update the UI in the child thread, and can not catch all the thread exception, finally, do not have the flexibility to implement the control thread execution order. Below we V1.1 version focus to support thread cancellation and resolution in child threads to update our UI. We know that the Futuretask interface supports cancellation, so we take futuretask as a member variable of class Myasynctask. Let's look at the following implementation of the V1.2 version:
Public abstract class Myasynctask<result> {private static final int core_pool_size = 5;
private static final int message_post_result = 0x1;
Here we create a new default core_pool_size size thread pool public static Executor Executor = Executors.newfixedthreadpool (core_pool_size);
To ensure that multiple threads cancel operations on Myasynctask, other threads are immediately visible to the private final atomicboolean mcancelled = new Atomicboolean ();
Protected final Internalhandler Shandler;
Private futuretask<result> Futuretask; Public Myasynctask () {if (Looper.mylooper ()!= looper.getmainlooper ()) {//When Myasynctask is not instantiated in the main thread, assign handler to Looper, and you can
Implementation in the child thread update main thread shandler = new Internalhandler (Looper.getmainlooper ());
else {Shandler = new Internalhandler (); Futuretask = new Futuretask<result> (new callable<result> () {@Override public result call () throws
Exception {return Postresult (Doinbackground ());//Here is asynchronous task Execution}}); Private result Postresult {message message = Shandler.obtainmessage (MEssage_post_result, New safeasynctaskresult<result> (This,result)); Message.sendtotarget ();
Task execution completes, messages are sent to the UI thread, and our message parameters are encapsulated into the object of the Safeasynctaskresult<result> class.
public void Execute () {onpreexecute ();
Executor.execute (Futuretask); * * * * When the asynchronous task starts before the operation/private void OnPreExecute () {} public Boolean cancel (Boolean mayinterruptifrunning)
{Mcancelled.set (true);
Return Futuretask.cancel (mayinterruptifrunning);
* * * Determine if the current task is canceled/public boolean iscanceled () {return mcancelled.get ();
/* * Implement this method, where the true asynchronous task executes/protected abstract result doinbackground ();
private static class Internalhandler<result> extends Handler {public Internalhandler () {super ();
Public Internalhandler (Looper looper) {super (Looper); public void Handlemessage (message msg) {safeasynctaskresult<result> result = (safeasynctaskresult< ;
result>) Msg.obj; Switch (msg.what){Case MESSAGE_POST_RESULT:result.mTask.finish (result.mdata);/Note here we handle it in hander.
Message_post_result (indicates completion of task execution) break;
}} private void finish (result result) {OnPostExecute (result);
* * * Task finishes updating UI/protected abstract void OnPostExecute (result result);
private Static class Safeasynctaskresult<data> {final Myasynctask mtask;
Final Data Mdata;
Safeasynctaskresult (myasynctask<?> task, data data) {mtask = task;
Mdata = data;
}
}
}
Then our V1.3 version focuses on controlling thread concurrency and threading collaboration, and in the V1.2 version our threading process directly establishes a fixed-size thread pool to handle the problem, with the default 4.0 and above, the Asynctask default thread pool linear execution series threads, and the serial threads can be executed in parallel. Here we see the source code 4.0 for the implementation of Asynctask control, we saw in the source code to initialize a concurrent thread pool Thread_pool_execute thread pool, while initializing a class serialexecutor, Let's look at the Serialexecutor code:
private static class Serialexecutor implements Executor {final arraydeque<runnable> mtask
s = new arraydeque<runnable> ();
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); }
}
}
We notice that the implementation of the Schedulenext method actually calls the Thread_pool_executor concurrent thread pool to execute threads, so that we know that the Asynctask control thread pool sequence executes on the task time by controlling the sequential execution of the concurrent thread pool to achieve the goal. By controlling the concurrent thread pool linear execution threads here, we can boldly say that we can also implement a more flexible control thread pooling implementation through encapsulation if we design reasonably. Given the limited level, it is not possible to write more flexible actuators that control the order in which threads are executed. Below we give the V1.3 version of the code implementation function, is very close to the system 4.0 of the Asynctask source implementation.
Public abstract class Myasynctask<result> {private static final int cpu_count = Runtime.getruntime (). Availablepro
Cessors ();
private static final int core_pool_size = Cpu_count + 1;
private static final int maximum_pool_size = Cpu_count * 2 + 1;
private static final int message_post_result = 0x1;
private static final int keep_alive = 1; private static final Threadfactory sthreadfactory = new Threadfactory () {private final Atomicinteger Mcount = new
Atomicinteger (1);
Public thread Newthread (Runnable r) {return new Thread (R, "Asynctask #" + mcount.getandincrement ());
}
}; private static final blockingqueue<runnable> Spoolworkqueue = new Linkedblockingqueue<runnable> (12
8);
public static final Executor serial_executor = new Serialexecutor (); public static final Executor thread_pool_executor = new Threadpoolexecutor (core_pool_size, Maximum_pool_size, Keep_al IVE, Timeunit.SECONDS, Spoolworkqueue, sthreadfactory); The Android source Asynctask implementation Sdefaultexecutor keyword volatile because the Setdefaultexecutor method can modify the Asynctask default implementation private static
Executor sdefaultexecutor = Serial_executor;
The task completes or cancels the callback interface private Aysnctaskfinishedlistener Finishlistener; private static class Serialexecutor implements Executor {final arraydeque<runnable> mtasks = new Arraydeque
<Runnable> ();
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);
}}//Ensure that multiple threads cancel operations on Myasynctask, other threads are immediately visible to the private final atomicboolean mcancelled = new Atomicboolean ();
Protected final Internalhandler Shandler;
Private futuretask<result> Futuretask; Public Myasynctask () {if (Looper.mylooper ()!= looper.getmainlooper ()) {//When Myasynctask is not instantiated in the main thread, assign handler to Looper, and you can
Implementation in the child thread update main thread shandler = new Internalhandler (Looper.getmainlooper ());
else {Shandler = new Internalhandler (); Futuretask = new Futuretask<result> (new callable<result> () {@Override public result call () throws
Exception {return Postresult (Doinbackground ());//Here is asynchronous task Execution}}); } protected void Setfinishedlistener (Aysnctaskfinishedlistener finishlistener) {This.finishlistener = FinishListener
; Private result Postresult {message message = Shandler.obtainmessage (Message_post_result, New Safeasy Nctaskresult<result> (This,result)); Message.sendtotarget ();
Task execution completes, messages are sent to the UI thread, and our message parameters are encapsulated into the object of the Safeasynctaskresult<result> class.
/* * Default thread linear execution/public void execute () {onpreexecute ();
Sdefaultexecutor.execute (Futuretask);
/* * Explicit call parallel execution/public void Executeonexecutor () {onpreexecute ();
Thread_pool_executor.execute (Futuretask); * * * * When the asynchronous task starts before the operation/private void OnPreExecute () {} public Boolean cancel (Boolean mayinterruptifrunning)
{Mcancelled.set (true);
Return Futuretask.cancel (mayinterruptifrunning);
* * * Determine if the current task is canceled/public boolean iscanceled () {return mcancelled.get ();
/* * Implement this method, where the true asynchronous task executes/protected abstract result doinbackground ();
private static class Internalhandler<result> extends Handler {public Internalhandler () {super ();
Public Internalhandler (Looper looper) {super (Looper); } public void Handlemessage (msg) {Safeasynctaskresult<result> result = (safeasynctaskresult<result>) msg.obj; Switch (msg.what) {case MESSAGE_POST_RESULT:result.mTask.finish (result.mdata);//Note
Here we deal with the Message_post_result in the hander (which indicates the execution of the task) break; }} private void finish (result result) {if (iscanceled ()) {if (Finishlistener!= null) finishlist
Ener.oncancelled ();
}else{OnPostExecute (Result);
if (Finishlistener!= null) Finishlistener.onpostexecute ();
}/* * Task finishes updating UI/protected abstract void OnPostExecute (result result);
private Static class Safeasynctaskresult<data> {final Myasynctask mtask;
Final Data Mdata;
Safeasynctaskresult (myasynctask<?> task, data data) {mtask = task;
Mdata = data;
} public static interface Aysnctaskfinishedlistener {void oncancelled ();
void OnPostExecute (); }
}
V1.3 code does not achieve a more flexible control of the thread pool to the code, we can do it by encapsulating the myasynctask operation. The following implementations refer to the implementation of the Android-lite-async project on GitHub, and the implementation of Myasynctask is as follows:
public class Taskexecutor {/** * Checkpoint asynchronous Task Executor * * @return/public static Cyclicbarrierexecutor
Newcyclicbarrierexecutor () {return new cyclicbarrierexecutor (); public static class Cyclicbarrierexecutor {arraylist<myasynctask<?>> taskList = new ArrayList
<MyAsyncTask<?>> ();
Public Cyclicbarrierexecutor put (myasynctask<?> Task) {if (Task!= null) Tasklist.add (Task);
return this;
public void Start (final myasynctask<?> finishtask) {start (finishtask, 0, NULL); "public void Start" (Final myasynctask<?> Endonuitask, final long time, final timeunit unit) {F
Inal Countdownlatch latch = new Countdownlatch (Tasklist.size ());
New Myasynctask<boolean> () {@Override protected Boolean Doinbackground () { try {if (unit= = null) latch.await ();
else latch.await (time, unit);
catch (Interruptedexception e) {e.printstacktrace ();
return true; } @Override protected void OnPostExecute (Boolean aboolean) {Endonuit
Ask.execute ();
}}.execute ();
Startinternal (latch); } private void Startinternal (final countdownlatch latch) {for (myasynctask<?> each:tasklist)
{Each.setfinishedlistener (new Myasynctask.aysnctaskfinishedlistener () {@Override
public void OnPostExecute () {Latch.countdown (); @Override public void oncancelled () {Latch.countdown ();
}
});
Each.execute ();
}
}
}
}
The above code we use Countdownlatch to control the sequence of sequential execution of threads, has been able to achieve our more flexible control code execution order. Through the above code analysis, about the implementation of Asynctask, are all around the handler + thread mode, but the package is strong or not. If you want to continue to learn more about Handler + thread encapsulation, you can learn to learn the Safeasynctask implementation of GitHub's Android client package. Ps:github's Android client is worth learning more than just Safeasynctask code encapsulation, and it's interesting to learn more about the entire code framework.
Through the above analysis, we also know that asynctask even if the optimization solves the above several sins (except 5th), our asynctask is not omnipotent. In our development, there are still a lot of threading interactions that can't be solved with aynctask, for example, the fifth question, and for example, when we two threads waiting for each other, such as task one request interface Data Return task second processing, task one wait for callback task two data, then continue to perform task one (PS: In our development, this situation is a large part of the reason is the interface interface too late to deal with or deal with the time, and finally, we can only hand over to our clients to solve.
Reprint please indicate the source: http://blog.csdn.net/johnnyz1234/article/details/47092227