1. AsyncTask 概述
官方已不再推荐使用,API 30 源码注释:
1
2
3
4
5
6
7
8
9
10
11/**
* bla bla bla
*
* @deprecated Use the standard <code>java.util.concurrent</code> or
* <a href="https://developer.android.com/topic/libraries/architecture/coroutines">
* Kotlin concurrency utilities</a> instead.
*/
@Deprecated
public abstract class AsyncTask<Params, Progress, Result> {
// bla bla bla
}AsyncTask 是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程中更新 UI
- AsyncTask 内部封装了线程池和 Handler,通过 AsyncTask 可以更加方便地执行后台任务以及在主线程中访问 UI
- AsyncTask 并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池
AsyncTask 是一个抽象的泛型类,提供了 Params、Progress 和 Result 这三个泛型参数
- Params 表示参数的类型,Progress 表示后台任务的执行进度的类型,Result 表示后台任务的返回结果的类型
- 如果 AsyncTask 确实不需要传递具体的参数,那么这三个泛型参数可以用 Void 来代替
- AsyncTask 类的声明为:
public abstract class AsyncTask<Params, Progress, Result>
AsyncTask 提供了 4 个核心方法,含义如下表:
核心方法 含义 onPreExecute()
在主线程中执行,在异步任务执行之前,此方法会被调用,一般可以用于做一些准备工作 doInBackground(Params... params)
在线程池中执行,此方法用于执行异步任务,params 参数表示异步任务的输入参数。在此方法中可以通过 publishProgress()
方法来更新任务的进度,publishProgress()
方法会调用onProgressUpdate()
方法。另外此方法需要返回计算结果给onPostExecute()
方法onProgressUpdate(Progress... values)
在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用 onPostExecute(Result result)
在主线程中执行,在异步任务执行之后,此方法会被调用,其中 result 参数是后台任务的返回值,即 doInBackground()
方法的返回值- AsyncTask 还提供了
onCancelled()
方法,同样在主线程中执行。当异步任务被取消时,onCancelled()
方法会被调用,此时onPostExecute()
方法不会被调用
- AsyncTask 还提供了
Demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled())
break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
// 执行下载任务
new DownloadFilesTask().execute(url1, url2, url3);AsyncTask 在具体的使用过程中的条件限制
- AsyncTask 的类必须在主线程中加载,即第一次访问 AsyncTask 必须发生在主线程,这个过程在 Android 4.1 及以上版本中已经被系统自动完成。在 Android 5.0 的源码中 ,可以查看 ActivityThread 的
main()
方法,它会调用 AsyncTask 的init()
方法,这就满足了 AsyncTask 的类必须在主线程中进行加载这个条件 - AsyncTask 的对象必须在主线程中创建;
execute()
方法必须在主线程中调用 - 不要在程序中直接调用
onPreExecute()
、onPostExecute()
、doInBackground()
和onProgressUpdate()
方法 - 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute() 方法,否则会报运行时异常
- 在 Android 1.6 之前,AsyncTask 是串行执行任务的,Android 1.6 时 AsyncTask 开始采用线程池处理并行任务。但从 Android 3.0 开始,为了避免 AsyncTask 带来的并发错误,AsyncTask 又采用了一个线程来串行执行任务。尽管如此,在 Android 3.0 及后续的版本,我们仍然可以通过 AsyncTask 的
executeOnExecutor()
方法来并行执行任务
- AsyncTask 的类必须在主线程中加载,即第一次访问 AsyncTask 必须发生在主线程,这个过程在 Android 4.1 及以上版本中已经被系统自动完成。在 Android 5.0 的源码中 ,可以查看 ActivityThread 的
2. AsyncTask 工作原理概述
AsyncTask 中有两个线程池: SerialExecutor 和 THREAD_POOL_EXECUTOR 和一个 Handler(InternalHandler)
- 线程池 SerialExecutor 用于任务的排队,线程池 THREAD_POOL_EXECUTOR 用于真正地执行任务
- Handler InternalHandler 用于将执行环境从线程池切换到主线程
execute(Param... params)
方法源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70/**
* Executes the task with the specified parameters. The task returns
* itself(this) so that the caller can keep a reference to it.
*
* <p>Note: this function schedules the task on a queue for a single background
* thread or pool of threads depending on the platform version. When first
* introduced, AsyncTasks were executed serially on a single background thread.
* Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operarte in parallel. Starting
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
* executed on a single thread to avoid common application errors caused
* by paralled execution. If you truly want paralel execution, you can use
* the {@link #executeOnExecutor} version of this method
* with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
* on its use.
*
* <p>This method must be invoked on the UI thread.
*
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} return either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execteOnExecutor(java.util.concurrent.Executor, Object[])
* @see #execute(Runnable)
*/
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executorOnExecutor(sDefaultExecutor, params);
}
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
* d
* @deprecated Globally serializing tasks results in excessive queuing for unrelated operations.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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 = mTask.poll() != null)) {
THREAD_POOL_EXECUTOR.executor(mActive);
}
}
}- sDefaultExecutor 是一个串行的线程池,一个进程中所有的 AsyncTask 全部在这个串行的线程池中排队执行
- 从 SerialExecutor 的实现可以分析 AsyncTask 的排队执行的过程。从 Android 3.0 开始,默认情况下 AsyncTask 是串行执行的
executeOnExecutor(Executor exec, Params... params)
方法源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54/**
* Executes the task with the specified parameter. The task returns
* itself(this) so that the caller can keep a reference to it.
*
* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.
*
* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
* a thread pool is generally <em>not</em> what one wants, because the order
* of their operation is not defined. For example, if these tasks are used
* to modify any state in common (such as writing a file due to a button click),
* there are no guarantees on the order of the modifications.
* Without careful work it is possible in rare cases for the newer version
* of the data to be over-written by an older one, leading to obscure data
* loss and stability issues. Such changes are best
* executed in serial; to guarantee such work is serialized regardless of
* platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
*
* @param params The parammeter of the task.
*
* @return This instance of AsyncTask.
*
* @throw IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status@RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see @execute(Object[])
*/
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execte task: " + "the task is already running.");
case FINISHED:
throw new IllegalStateException("Canot execute task: " + "the task has already been executed " + "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execte(mFuture);
return this;
}executeOnExecutor()
方法中,AsyncTask 的onPreExecute()
方法最先执行,然后线程池开始执行
构造方法
AsyncTask(Looper)
源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static InternalHandler sHandler;
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private final Handler mHandler;
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler() : new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result> () {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG.TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
// 私有的静态内部类
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
"unchecked", "RawUseOfParamterizedType"}) ({
public void handleMessage() {
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;
}
}
}
"RawUseOfParameterizedType"}) ({
private static class AsyncTaskResult<Data> {
final AsyncTask = mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
private Handler getHandler() {
return mHandler;
}
private Result postResult(Result result) {
"unchecked") (
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package java.util.concurrent;
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* <p>The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
* <p>The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} clases.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package java.util.concurrent;
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullpointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}- sHandler 是一个静态的 Handler 对象,为了能够将执行环境切换到主线程,这就要求 sHandler 这个对象必须在主线程中创建。由于静态成员会在加载类的时候进行初始化,因此这就变相要求 AsyncTask 的类必须在主线程中加载,否则同一个进程中的 AsyncTask 都将无法正常工作
3. HandlerThread 概述
HandlerThread 继承了 Thread,是一种可以使用 Handler 的 Thread。HandlerThread 源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
/**
* A {@link Thread} that has a {@link Looper}.
* The {@link Looper} can then be used to create {@link Handler}s.
* <p>
* Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
pubic Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
// bla bla bla
}- 从类注释可知,HandlerThread 的
start()
方法仍然需要手动调用 - HandlerThread 和普通的 Thread 有显著区别:普通 Thread 主要用于在
run()
方法中执行一个耗时任务;HandlerThread 在内部创建了消息队列,外界需要通过 Handler 的消息方式来通知 HandlerThread 执行一个具体的任务
- 从类注释可知,HandlerThread 的
HandlerThread 的
run()
方法源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}- 实现很简单,就是在
run()
方法中通过Looper.prepare()
来创建消息队列,并通过Looper.loop()
来开启消息循环,这样在实际使用中就允许在 HandlerThread 中创建 Handler - 因为
Looper.loop()
方法是一个无限循环,所以 HandlerThread 的run()
方法也是一个无限循环。因此当明确不需要再使用 HandlerThread 时,可通过调用 HanlderThread 的quit()
或quitSafely()
方法来终止线程的执行
- 实现很简单,就是在
HandlerThread 是一个很有用的类,在 Android 中的一个具体使用场景是 IntentService
4. IntentService 概述
Android 8.0 以下版本官方已不推荐使用,API 30 源码注释:
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* bla bla bla
*
* @deprecated IntentService is subject to all the
* <a href="/preview/features/background.html">background execution limits</a>
* imposed with Android 8.0 (API level 26). Consider using {@link androidx.work.WorkManager}
* or {@link androidx.core.app.JobIntentService}, which uses jobs
* instead of services when running on Android 8.0 or higher.
*/
public abstract class IntentService extends Service {
// bla bla bla
}IntentService 继承了 Service 并且是一个抽象类,因此必须创建它的子类才能使用 IntentService
IntentService 可用于执行后台耗时的任务,当任务执行完成后会自动停止。同时由于 IntentService 是服务的原因,所以优先级比单纯的线程高很多,所以 IntentService 比较适合执行一些高优先级的后台任务
在实现上,IntentService 封装了 HandlerThread 和 Handler。
onCreate()
方法源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
public void handleMessage() {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
protected abstract void onHandleIntent(@Nullable Intent intent);- 当 IntentService 被第一次启动时,它的
onCreate()
方法会被调用,onCreate()
方法会创建一个 HandlerThread,然后使用它的 Looper 来构造一个 Handler 对象 mServiceHandler。这样通过 mServiceHandler 发送的消息最终都会在 HandlerThread 中执行,从这个角度看,IntentService 也可以用于执行后台任务 onHandleIntent()
是一个抽象方法,需要在子类中实现,作用是从 Intent 参数中区分具体的任务并执行
- 当 IntentService 被第一次启动时,它的
每次启动 IntentService,它的
onStartCommand()
方法就会调用一次,IntentService 在onStartCommand()
方法中处理每个后台任务的 Intent。onStartCommand()
方法源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private boolean mRedelivery;
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}- IntentService 仅仅是通过 mServiceHandler 发送了一个消息,这个消息会在 HandlerThread 中被处理。mServiceHandler 收到消息后,会将 Intent 对象传递给
onHandleIntent()
方法处理 - 当
onHandleIntent()
方法执行结束后,IntentService 会通过stopSelf(int startId)
方法来尝试停止服务。stopSelf(int startId)
方法会等待所有的消息都处理完才终止服务,stopSelf()
方法会立刻停止服务(有点类似quit()
和quitSafely()
的区别),服务停止是会回调onDestroy()
方法 - 由于每执行一个后台任务就必须启动一次 IntentService,而 IntentService 内部通过消息的方式向 HandlerThread 请求执行任务,Handler 中的 Looper 是顺序处理消息的,这就意味着 IntentService 也是顺序执行后台任务的,即当有多个后台任务同时存在时,这些后台任务会按照外界发起的顺序排队执行
- IntentService 仅仅是通过 mServiceHandler 发送了一个消息,这个消息会在 HandlerThread 中被处理。mServiceHandler 收到消息后,会将 Intent 对象传递给