一、AsyncTask的简介以及使用
1、AsyncTask的简介
一个Android轻量级异步类;实际上在我们日常开发中可能会遇到大量子线程处理数据然后回调到主线程进行展示处理等需求,因此谷歌官方将线程池+Handler封装成了AsyncTask,方便开发者使用。
2、使用
public class TestActivity extends BaseActivity {
private TextView tv_progress;
@Override
public void init() {
Button btn_click = (Button) findViewById(R.id.btn_click);
tv_progress = (TextView) findViewById(R.id.tv_progress);
final MyTestAsyncTask myTestAsyncTask = new MyTestAsyncTask(this);
btn_click.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myTestAsyncTask.execute();
}
});
}
@Override
public int getContentViewId() {
return R.layout.activity_main;
}
private static class MyTestAsyncTask extends AsyncTask<Integer, Integer, String> {
private final WeakReference<TestActivity> mReference;
private MyTestAsyncTask(TestActivity testActivity) {
mReference = new WeakReference<>(testActivity);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
mReference.get().tv_progress.setText("准备开始加载 onPreExecute");
}
@Override
protected void onCancelled() {
super.onCancelled();
mReference.get().tv_progress.setText("onCancelled");
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
mReference.get().tv_progress.setText("加载成功 onPostExecute");
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mReference.get().tv_progress.setText("进度:" + values[0]);
}
@Override
protected String doInBackground(Integer... integers) {
int count = -1;
while (count <= 100) {
publishProgress(count);
count++;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
其中onPreExecute(实际异步处理前的回调一般用于初始化控件状态)、onCancelled(异步任务被取消时的回调)、onPostExecute(线程任务执行结束后自动调用,当onCancelled被调用了,该方法不会回调)、onProgressUpdate(publishProgress调用时调用,用来更新进度等)都在主线程中调用;doInBackground实际处理异步请求,在工作线程中调用。
二、AsyncTask的原理
AsyncTask的原理总结来说就是两个线程池+1个Handler,其中SERIAL_EXECUTOR用来任务排队;THREAD_POOL_EXECUTOR用来实际处理任务;sHandler用来回调主线程。
具体根据源码来看:
1、构造方法
public AsyncTask() {
//workerRunnable是一个CallBack,代表了AsyncTask要执行的任务
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
//执行doInBackground 开始异步执行任务
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
//CallBack要放在FutureTask执行;因此创建一个FutureTask并把mWorker当做参数传进来
mFuture = new FutureTask<Result>(mWorker) {
@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);
}
}
};
}
构造方法中创建了一个workerRunnable(本质上是一个Callback),mWorker代表了AsyncTask要实际进行异步处理的任务,doInbackground在mWorker被调用;有了Callback要有FuturTask进行接收,因此后面有初始化一个mFuture并把mWorker当做参数传进来;
2、execute()方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//实际调用executeOnExecutor
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//在execute调用后会判断一些标志位,如果AsyncTask正在运行处于RUNNING状态
//多次调用execute可能会抛出异常
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)");
}
}
//修改当前的标志位为RUNNING状态
mStatus = Status.RUNNING;
//调用onPreExecute方法 执行异步前的准备阶段
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
execute实际调用了executeOnExecutor方法,进行状态判断并修改状态位;调用OnPreExecute方法;最后通过exec.execute(mFuture)把构造函数中创建好的FutureTask传进来;exec.execute的exec为串行线程池SERIAL_EXECUTOR(实际为AsyncTask的内部类SerialExecutor)
SerialExecutord的execute分析
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就是前面传过来的mFutureTask->执行FutureTask的run方法
//->由于FutureTask中传进来的是mWorker,因此这里的run实际执行的就是mWorker
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
//保证任务的串行执行
protected synchronized void scheduleNext() {
//取出任务队列头部的任务
if ((mActive = mTasks.poll()) != null) {
//实际调用THREAD_POOL_EXECUTOR执行任务
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
SerialExecutord的execute方法是加锁的,保证了任务的按照执行循序排队;将mFuture保存在mTasks队列中;执行scheduleNext方法从队列头部去除元素,并调用THREAD_POOL_EXECUTOR线程池的execute方法进行实际的任务调度执行。
THREAD_POOL_EXECUTOR分析
//获取当前设备CPU的核心数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//线程池的核心线程数2-4之间,取决于CPU核心
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//线程池的最大线程数 2*CPU数量 + 1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空闲线程存活时间30s
private static final int KEEP_ALIVE_SECONDS = 30;
//初始化线程工厂
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);
public static final Executor 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;
}
3、mWorker分析
上面讲完了workerRunnable在AsyncTask的构造中创建完成,此后在THREAD_POOL_EXECUTOR进行调度执行;下面分析一下mWorker的源码:
//WorkerRunnable本质是一个Callable
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//添加线程的调用标识
mTaskInvoked.set(true);
Result result = null;
try {
//设置线程的优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//执行耗时操作(即我们自己复写的doInBackground方法在此刻被调用)
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
//若发生异常 中断标志位置为true
mCancelled.set(true);
throw tr;
} finally {
//把异步任务的执行结果发送给主线程
postResult(result);
}
return result;
}
};
4、postResult()异步任务如何发送给主线程?
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//将result封装成一个message
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler() {
//获取主线程的Looper 创建主线程Handler
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;
}
}
}
通过利用MainLooper创建主线程Handler将Message发送给主线程;至此AsyncTask完成了从创建->任务处理调用->result回调给主线程。
网友评论