多线程系列历史文章:
Android/java 多线程(一)-Thread的使用以及源码分析
Android/java 多线程(二)-Thread的好兄弟Handler
Android/java 多线程(三)-HandlerThread的使用场景及源码解析
Android/java多线程(四)-IntentService
Android/java 多线程(五)-ThreadPoolExecutor线程池的使用
简介
一个Android封装好的轻量级异步抽象类,使用的话需要继承并重写部分方法
作用
方便的实现多线程,并能方便的实现主线程与工作线程的通信,并且逻辑都在一个类中,不同于Handler的实现机制在不同的回调中,内部采用线程池管理策略,方便管理
使用介绍
public abstract class AsyncTask<Params, Progress, Result> {
....
}
可以看到有三个泛型参数,它们的作用分别是:
- Params 传递给异步任务的参数类型,对应execute()方法和doInBackground()中的参数类型
- Progress 进度跟新参数类型,对应onProgressUpdate()方法返回的参数类型
- Result 异步任务执行完毕的返回结果类型,对应doInBackground()方法的返回结果类型和onPostExecute()方法的参数类型
如果不需要使用到,则可以使用Void
类代替
简单示例:
申明一个实现类TestAsyncTask,主要打印方法的执行顺序以及参数及运行的线程名称
/**
* Created by hj on 2018/12/29.
* 说明:
*/
public class TestAsyncTask extends AsyncTask<String,Integer,Integer> {
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
Log.i("HJ","onPostExecute方法接收的参数值:"+integer+"--"+runThreadName());
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i("HJ","onPreExecute"+"--"+runThreadName());
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i("HJ","onProgressUpdate:"+ Arrays.toString(values)+"--"+runThreadName());
}
@Override
protected Integer doInBackground(String... strings) {
Log.i("HJ","doInBackground()"+"--"+runThreadName());
publishProgress(50);
return 1;
}
private String runThreadName(){
return "运行在:"+Thread.currentThread().getName()+"线程";
}
}
使用:
//必须是在主线程中
TestAsyncTask task = new TestAsyncTask();
task.execute();
打印结果:
I/HJ: onPreExecute--运行在:main线程
I/HJ: doInBackground()--运行在:AsyncTask #1线程
I/HJ: onProgressUpdate:[50]--运行在:main线程
I/HJ: onPostExecute方法接收的参数值:1--运行在:main线程
可以看到,只有doInBackground()方法执行在异步线程中,其他的方法都是运行在主线程中,方法执行顺序为:
onPreExecute()—->doInBackground()—->调用publishProgress()方法—->onProgressUpdate()——>onPostExecute()
下面介绍一下方法的具体作用:
- onPreExecute 在进行异步任务处理前的一些数据准备工作
- doInBackground 处理异步任务逻辑,内部可以调用publishProgress更新进度
- onProgressUpdate 进度更新回调
- onPostExecute 异步处理完毕后的结果回调 ,处理ui逻辑
源码解析
AsyncTask
内部的实现原理为:线程池+Handler
其内部有两个线程池:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor THREAD_POOL_EXECUTOR;
SERIAL_EXECUTOR
对应内部的SerialExecutor
内部实现类,主要实现了异步任务的顺序分发:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive; //当前要处理的异步任务
//给execute方法加锁保证了顺序执行
public synchronized void execute(final Runnable r) {
//将一个runnable添加进双端队列中
mTasks.offer(new Runnable() {
public void run() {
try {
r.run(); //执行
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
//此方法的作用是将SerialExecutor 池中的任务的第一个任务赋值给mActive ,并压入到
//THREAD_POOL_EXECUTOR线程池中
protected synchronized void scheduleNext() {
//poll()方法的作用是删除队列中的第一个并返回结果,如果为null则返回null
if ((mActive = mTasks.poll()) != null) {
//将第一个任务添加到THREAD_POOL_EXECUTOR线程池中
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
而THREAD_POOL_EXECUTOR的实现是在这里:
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
可以看出它是一个常见的工作线程池,所以,这两个线程池,一个负责消息的任务调度,保证按照顺序执行,另外一个则是真正的异步任务处理池
接下来看一下它的构造方法:
public AsyncTask(@Nullable Looper callbackLooper) {
//初始化一个Handler处理主线程的通信
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//初始化一个可以存储Params参数的callable实现,其实也是
//THREAD_POOL_EXECUTOR.execute()的执行回调
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//里面的回调是不是很熟悉,和HandlerThread类似
mTaskInvoked.set(true); //添加线程标识,用于postResultIfNotInvoked方法的检查
Result result = null; //这就是onPostExecute()方法的result
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams); //doInBackground方法在这里执行了
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true); //抛异常了取消任务
throw tr;
} finally {
postResult(result); //此方法的作用是将结果发送到主线程
}
return result;
}
};
//初始化一个Future回调,主要用于检查处理结果是否发送
mFuture = new FutureTask<Result>(mWorker) {
//done()方法是在callable()方法之后的回调
@Override
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);
}
}
};
}
//mWorker 的实现
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams; //保存传入的参数
}
接下来看看以上检查的方法的实现:
private void postResultIfNotInvoked(Result result) {
//执行了mWorker 里的call()回调的都会变为true,如果为false,说明任务没有被执行
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
//将此AsyncTask对象作为message参数发送,接收到之后就会调用finish()方法结束
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
其中的getHandler()中的Handler的实现类是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:
//result.mData[0]就是从postResult发送过来的AsyncTask对象
result.mTask.finish(result.mData[0]); //处理结果分发,回调对应的方法
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData); //这里处理进度更新
break;
}
}
}
private void finish(Result result) {
// 先判断是否调用了Cancelled()
// 1. 若调用了则执行我们复写的onCancelled()
// 即 取消任务时的操作
if (isCancelled()) {
onCancelled(result);
} else {
// 2. 若无调用Cancelled(),则执行我们复写的onPostExecute(result)
// 即更新UI操作
onPostExecute(result);
}
// 注:不管AsyncTask是否被取消,都会将AsyncTask的状态变更为:FINISHED
mStatus = Status.FINISHED;
}
最后来看一下执行方法execute()
:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
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)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params; //mWorker中的参数是在这里保存的
exec.execute(mFuture); //将mFuture对象添加到THREAD_POOL_EXECUTOR 线程池中,mFuture在构造方法中做了初始化。
return this;
}
总结:
1.初始化两个线程池,一个负责任务调度(SerialExecutor)
,一个负责任务处理THREAD_POOL_EXECUTOR
2.构造方法中实例化了子线程中的callable接口方法,从WorkerRunnable
中取出Params
对象并赋值给dodoInBackground(mParams)
方法执行耗时任务。
3.执行execute()
方法将任务提交到THREAD_POOL_EXECUTOR线程池中,并将Params参数赋值到了WorkerRunnable
中。
4.调用了postResult(result)
,通过InternalHandler 将消息回调到了主线程(执行了finish()方法,里面有onPostExecute方法),实现了UI的更新