您的位置:首页 > 其它

AsyncTask的简单理解(源码级)

2015-11-10 13:54 253 查看

AsyncTask的简单理解

AsyncTask里面有两个线程池
ThreadPoolExecutor
SerialExecutor
还有一个
Handler
。,其中
SerialExecutor
用来给线程排队,真正执行的是
ThreadPoolExecutor
Handler
用于线程之间的切换。给AsyncTask排队的容器是一个单向队列
ArrayDeque<Runnable>
,他保存了所有将要执行的线程。先来看一下熟悉的
execute
方法

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}


他调用了executeOnExecutor方法,同时把用于排队的线程池和在doInBackground需要用到的参数传进去。

@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;
exec.execute(mFuture);

return this;
}


这个方法执行在主线程,他调用了
onPreExecute()
,所以说
onPreExecute()
在主线程调用。然后他使用了
exec.execute(mFuture);
来排队,这里的exec就是上面传过来的
sDefaultExecutor
,也就是用于排队的线程池。那么他的参数
mFuture
是什么呢。他是一个
FutureTask
简而言之就是监控一条线程的执行状态。他在构造器里面进行初始化,我们来到构造器。

public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};

mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
......
}
};
}


上面代码中
WorkerRunnable
是一个抽象类,他封装了Params[],
WorkerRunnable
也实现了
Callable<Result>
接口,用于把这条线程放到
FutureTask
里面进行执行。
FutureTask
会自动调用
WorkerRunnable
里面重写的
call()
方法,而在这个
call()
正有我们熟悉的
doInBackground(mParams);
doInBackground();


如何处理结果

当运行结束后,返回一个result,由于他运行在子线程里面,需要把结果提交到主线程来显示,所以他会调用
postResult(result);
来显示结果。线程之间的切换用的是Handler。

private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}

@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;
}
}
}


上面是Handler如果处理结果。运行到
result.mTask.finish(result.mData[0]);
他会执行

private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}


看到
onPostExecute(result)
了吧,他就是用于接受结果的回调方法。由于用到了Handler切换线程,所以他运行在主线程。

如何更新进度

我们都知道在子线程里面更新进度需要调用
publishProgress
方法。

@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}


首先在消息池里面获取到
MESSAGE_POST_PROGRESS
消息。然后把
AsyncTaskResult<Progress>
的实例放到里面。这个
AsyncTaskResult<Progress>
是什么呢?

private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;

AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}


他是一个静态类,构造器里面封装的AsyncTask和需要被更新的值。

然后
Handler
会把它发送到what为
MESSAGE_POST_PROGRESS
的消息中,用来更新进度。

线程池是如何工作的。

1.排队线程池,先看代码

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);
}
}
}


他也是一个静态类,实现了
Executor
,并重写了execute方法。里面维护这一个
ArrayDeque
他是一个单向的队列。这里用到了他的两个方法。
offer()
poll()
,其中
offer()
方法是向队列最后面插入一条数据mTasks,
poll()
是从队列的最前面取出一条数据并将其删除。

他在插入的同时新建一个
Runable
同时执行了传入这条线程的
run()
方法。这里你也许要问,为什么一
Runable
要套一个
Runable
呢,既然是排队那么为什么要运行
run()
方法呢?

1、如果这个
Runable
如果不包含一个
Runable
,那么这个传进来的
Runable
就会直接执行的,注意,是执行在主线程。另外一个线程池没有起到作用。

2、这里虽然运行了
run()
方法真的线程也没有执行,里面线程虽然调用了
run()
方法,仅仅是调用而已,外面的Runable没有执行,里面的
run()
方法就不会执行。

排队之后他会执行
scheduleNext();
方法,这个方法是启动分线程的关键。他先从队列中取出
Runable
,然后调用
ThreadPoolExecutor
execute()
方法来真正执行线程。

线程池的参数

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
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 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>(128);


自己看吧,谷歌写的很明白
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程池 线程 asynctask