Introduction
AsyncTask
It is a simple class provided by the Android platform for performing asynchronous tasks in the background without blocking the main thread to maintain the responsiveness of the user interface. It can be used to handle some time-consuming operations, such as network requests, database queries, etc.
Interestingly, AsyncTask
it’s like a hard-working little assistant that can help you do some heavy work in the background, while you can continue to focus on other things, such as drinking a cup of coffee or playing mobile games.
However, AsyncTask
it has been officially marked as deprecated in the latest version of Android. This is because AsyncTask
of some potential issues and limitations, such as:
- Memory Leak : If
AsyncTask
is not canceled or completed correctly, it can cause a memory leak because it holds a reference to an external object. - Configuration change issue : When the screen is rotated or the configuration is changed,
AsyncTask
saving and restoring the state may not be handled correctly, resulting in data loss or other abnormalities. - Concurrency limit :
AsyncTask
By default, a single background thread is used to execute tasks, which means that only one task can be executed at the same time. In some scenarios, multiple tasks may need to be executed in parallel, andAsyncTask
this demand cannot be met.
In fact, all the above problems can be solved through code design, but this article is to introduce the “outdated” ones AsyncTask
, so I won’t introduce them in too much. Common methods are to onDestroy
release references in time, or to temporarily save data for subsequent use.
However, thinking too much about exception cases defeats AsyncTask
the original intention of choosing. Therefore, Android officially recommends other asynchronous task processing methods.
So, although AsyncTask
it was a commonly used tool in developing Android applications in the past, it has now been officially deprecated and developers should prioritize using more modern ways of handling asynchronous tasks.
Source code
The key to thread communication: Handler
Internally AsyncTask
, it maintains a static InternalHandler
class that extends from Handler
. This InternalHandler
is used to send messages to the main thread in a background thread.
The following is the definition AsyncTask
in the source code InternalHandler
:
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;
}
}
}
In AsyncTask
, when it needs to send a message, it creates an Message
object and sends it to InternalHandler
.
AsyncTask
There is a method named in the source code for postResult()
sending task result messages. Below is postResult()
the code snippet of the method
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
By using InternalHandler
and Message
, AsyncTask
a mechanism for message passing between the background thread and the main thread is implemented. The background thread can send messages to the main thread by calling the postResult()
or postProgress()
method, and the in the main thread InternalHandler
will receive these messages and perform corresponding operations, such as calling the onPostExecute()
or onProgressUpdate()
method to update the UI.
AsyncTask
Two Executors in
AsyncTask
There are two Executors, one SERIAL_EXECUTOR
is a serial execution Executor, which ensures that all tasks are executed in the order in which they are submitted. This is useful for situations where you need to avoid multiple tasks accessing a shared resource at the same time, because it ensures that one task is completed before the next task is executed. The specific code + comments are as follows:
//
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);
}
}
}
The other one is: THREAD_POOL_EXECUTOR
, the official explanation is translated and posted below:
An Executor that can be used to execute tasks in parallel.
It has been deprecated that using a single thread pool for different tasks can lead to sub-optimal behavior. Small -CPU-intensive tasks can benefit from a bounded pool and queue, while long-blocking tasks, such as network operations, can benefit from multiple threads. Please use or create an Executor configured to match your usage.
In other words, a serial execution thread pool was previously set up to ensure that tasks can be called in an orderly manner, but the serial blocking is too strong, so a parallel thread pool is added to speed up the thread’s work efficiency. .
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), sThreadFactory);
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
It is used here SynchronousQueue
as a task queue, which can quickly respond to tasks in a one-to-one producer-consumer format.