AsyncTask is designed to be a helper class around
Thread
andHandler
and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)
AsyncTask
It is used to help us better use Thread
andHandler
, best treatment for a short time asynchronous tasks.
Use AsyncTask to solve asynchronous problems
// AsyncTask
class MyAsyncTask(val name: String) : AsyncTask<Params, Progress, Result>() {
// Visible
override fun onPreExecute() {
Log.d("async", "onPreExecute")
}
// onPreExecute()
override fun doInBackground(vararg params: String?): Any? {
Log.d("async", "$name execute")
Thread.sleep(1000)
publishProgress(1)
return null
}
// publishProgress()
override fun onProgressUpdate(vararg values: Int?) {
Log.d("async", "progress is: $values")
}
//
override fun onPostExecute(result: Any?) {
Log.d("async", "onPostExecute")
}
}
//
MyAsyncTask("one").execute("")
MyAsyncTask("two").execute("")
MyAsyncTask("three").execute("")
MyAsyncTask("four").execute("")
//
19:29:01.472 1786-1805/com.taonce D/async: one execute
19:29:02.514 1786-1832/com.taonce D/async: two execute
19:29:03.868 1786-1833/com.taonce D/async: three execute
19:29:04.871 1786-1833/com.taonce D/async: four execute
AsyncTask
It must be instantiated by a subclass before it can be used. The methods that must be implemented are:, The doInBackground(vararg params: String?): Any?
other three methods are optional. The specific explanations are explained in the code above. There are three generic parameters left, which are explained one by one below:
-
Params
: Information needed to perform the task; -
Progress
: The progress released to the outside world during the execution of the task; -
Result
: The result after the task is completed.
So far, have you found a phenomenon? In the information printed in the result, each log is separated by 1s. Take a closer look to see if it is not. I will leave a pit for the time being. I will analyze it for everyone later. Start to enter the source code analysis below:
Constructor
1. simply analyze the code in the constructor:
public AsyncTask(@Nullable Looper callbackLooper) {
// mHandler callbackLooper sMainLooper getMainHandler() Handler
// callbackLooper
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// WorkerRunnable Callable call()
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
...
}
};
// FutureTask mWorker
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
...
}
};
}
mWorker
And mFuture
temporarily analysis, until the call of our combined source, at present, we need to know initialize these objects is enough.
execute()
Then we take a look at the entry point to perform a task execute()
:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// executeOnExecutor(executor,params), sDefaultExecutor
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
// execute()
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
// Running
mStatus = Status.RUNNING;
// onPreExecute(),
onPreExecute();
// params mWorker
mWorker.mParams = params;
// sDefaultExecutor.execute(runnable)
exec.execute(mFuture);
//
return this;
}
We call the AsyncTask.execute(parasm)
method is actually invoked sDefaultExecutor.execute(mFuture)
method, we follow it down.
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
//
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
// runnable.run()
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
// r.run() scheduleNext()
// Runnable Runnable
// 1s
scheduleNext();
}
}
});
//mActive
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
// Runnable
//THREAD_POOL_EXECUTOR
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
SerialExecutor
Is a realization Executor
of a static inner class, it execute(runnable)
receives the Runnable
object, and then executeOnExecutor(Executor exec, Params... params)
pass the method is mFuture
an object, so the execution scheduleNext()
time, it will call mFuture
the run()
method.
FutureTask.run()
:
public void run() {
...
try {
// Callable
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// Callable.call()
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
// Callable.call() set() get()
set(result);
}
}...
}
FutureTask.run()
Its method is to call Callable
the variable call()
method, AsyncTask
in the passed Callable
is mWorker
an object, this time we can put in the constructor mWorker
initialization code to read out the.
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// doInBackground(params)
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
// mCancelled true
mCancelled.set(true);
throw tr;
} finally {
//
postResult(result);
}
return result;
}
};
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
mWorker
Actually very simple, is to get doInBackground(params)
the return value, whether or not abnormal, the result will be a callback to the main thread, the callback operations appears below to seepostResult(result)
private Result postResult(Result result) {
//getHandler() mHandler Looper
// mHandler sHandler
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
By getHandler().obtainMessage()
obtaining an Message
object, the message what
to MESSAGE_POST_RESULT
mark is not the result of progress, obj
to AsyncTaskResult
the object, which is an internal class that contains AsyncTask
and Data[]
two parameters. By sHandler
sending out a message, and then we will see how itonPostExecute(result)
link up.
sHandler
They are InternalHandler
examples from our InternalHandler
source code will be able to get the answer you want:
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
//
switch (msg.what) {
case MESSAGE_POST_RESULT:
//There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
InternalHandler
Judgment message types, one is the result, one is progress, if it is the result, then it calls AsyncTask
the finish()
method; if it is progress, then calls the onProgressUpdate()
method, which in front has been introduced, and is updated overall the method of progress, as long as we look at finish()
methods to ok:
private void finish(Result result) {
//
if (isCancelled()) {
// onCancel()
onCancelled(result);
} else {
// onPostExecute()
onPostExecute(result);
}
// FINISHED
mStatus = Status.FINISHED;
}
Source code analysis to this case, roughly process has been completed, the execute()
method adds the tasks to be performed to SerialExecutor
the double-ended queue, and then let the THREAD_POOL_EXECUTOR
thread pool to order execution queue FutureTask.run()
to note here, mission is a an executive, After the execution is over, another one is executed. This thread pool is equivalent to a single-threaded mode, which executes tasks in serial rather than parallel execution. Only one core thread is actually working in the entire thread pool. By performing
FutureTask.run()
the method to perform the indirect mWorker.call()
methods, the call()
method for obtaining the doInBackground()
results of the method returned by the last postResult()
and InternalHandler
to the results of the callback onPostExecute()
method.
The article on source code analysis is still being updated. If you find any errors or deficiencies in this article, you are welcome to leave a message below or scan the QR code below to leave a message!