但凡接触过Android开发的人都知道UI线程是不能进行耗时操作的,否则有可能出现ANR。那么为了避免这个问题Android提供了AsyncTask来处理耗时任务如网络请求,数据库的读取等。那么接下来让我们看看AsyncTask是怎么实现的吧。
首先来看看AsyncTask的使用:
public classMainActivity extends AppCompatActivity {
public static finalStringTAG="MainActivity";
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//任务串行执行
new MyTask().execute("");
//任务并行执行
new MyTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECU TOR,"");
}
private static classMyTask extends AsyncTask {
//在执行任务之前调用(UIThread)
@Override
protected voidonPreExecute() {
super.onPreExecute();
Log.e(TAG,"onPreExecute:"+Thread.currentThread().getName());
}
//在执行任务执行时调用(WorkThread)返回值传入onPostExecute
@Override
protected String doInBackground(String... params) {
//耗时操作代码
try{
for(inti =0;i <5;i++) {
Thread.sleep(1000);
onProgressUpdate(i*20);
}
}catch(InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG,"doInBackground:"+Thread.currentThread().getName() );
return null;
}
//在执行任务执行百分比(WorkThread)
@Override
protected voidonProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.e(TAG,"onProgressUpdate:"+Thread.currentThread().getName() );
}
//在执行任务执行完成调用(UIThread)
@Override
protected voidonPostExecute(String s) {
super.onPostExecute(s);
Log.e(TAG,"onPostExecute:"+Thread.currentThread().getName());
}
}
}
源码分析
AsyncTask如何工作?
首先来看execute()和executeOnExecutor()方法:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);}
在这方法中会执行executeOnExecutor()这个方法,在这方法中又干了什么?
@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()--> exec.execute(mFuture);
exec就是execute方法传入的也就是sDefaultExecutor这个线程池,那我们再来看看这个线程池的定义及实现:
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.*/
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 = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
这个线程池也就是串行器的实现,我们来分析下它的实现:
首先是
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
这是一个线性的双向队列,用于存储AsyncTask任务,当有新的任务时就是调用mTasks.offer()(此方法将指定的元素,在此deque队列的末尾);然后执行scheduleNext();在这方法中会执行队列中排列最前的任务THREAD_POOL_EXECUTOR.execute(mActive);
下面是THREAD_POOL_EXECUTOR的定义:
/** * An {@link Executor} that can be used to execute tasks in parallel. */
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看出线程池核心容量的容量是cpu核心数 +1;线程池最大容量为cpu核心数* 2 + 1;过剩的空闲线程的存活时间为1秒;待执行的任务队列初始容量:128个 。
通过上面的分析可以知道,不管是串行执行任务还是并行执行,其中的区别就是传入给executeOnExecutor()的线程池的不同,串行就是sDefaultExecutor,当然也可以指定自己定义的串行器,而并行则可以自己指定线程池来执行。
分析完任务的串行和并行的执行之后,接下来来看看doInBackground()是何时开始执行以及是如何将执行结果返回给onPostExecute()的:首先在AsyncTask的构造方法中定义了个WorkerRunnable<Params, Result> implements Callable<Result>和一个FutureTask,不了解Callable和Future的可以看这里,我们看下构造方法中WorkerRunnable的实现
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//任务开始执行
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}};
通过上面代码可以发现执行后将结果交给postResult(result)方法处理,那我们在来看看这个方法的实现:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
看到这个方法后就明白了,AsyncTask的原理就是封装了handler+Thread。
总结:
AsyncTask内部封装了Thread和Handler,调用AsyncTask的executeOnExecutor方法可以实现任务的并行执行也可以自定义线程池,调用execute方法可以实现任务的串行执行。
网友评论