题外篇:最近开始看各种面试题,你懂的,然后发现看的东西老是记不住,于是去技术群里发了牢骚,然后行业大佬说:对着源码,自己撸一篇文章。当时我的心里是拒绝的,因为懒啊,也因为贪,认为只看不写,能看的更多些,但记不住也是没用,就听大佬的,撸一篇试试,这是写文章的原由,好,闲言少叙,切入正题。
顺藤摸瓜篇:打开Android studio,默认打开的是我写练习的一个service类,这不重要,找个空的地方反手就是一个New,约会的方式有很多种,但这不重要,重要的是我们约到了AsyncTask(API26)
AsyncTask mAsync = new AsyncTask() { @Override protected Object doInBackground(Object[] objects) { return null; } };
接下来我又随便找了个方法地方搞了这个
看到execute点进去看看咯
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
execute调用了executeOnExecutor,从方法的结构上可以看出,execute中并没有开启新的线程,所以它还是运行在当前线程的,当然execute这个方法还有个重载,那个并不是我们想要的,忽略了,在往下走之前,我们先看看execute这个方法上边点一大堆解释(只复制一次,后面的就不往文章里面复制了)
/** * Executes the task with the specified parameters. The task returns * itself (this) so that the caller can keep a reference to it. * * 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 operate 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 parallel execution. If you truly want parallel 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. * * 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()} returns either * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. * * @see #executeOnExecutor(java.util.concurrent.Executor, Object[]) * @see #execute(Runnable) */看到这些,我是头大点,但是踏下心来还是能看懂的,看我的神翻译, 前两行大概说,带参数执行,返回自己以便调用者持有任务的引用(返回自身引用的点好处还可以写链式代码,一直点点点直到结束的那种)。然后接着看下面有Note: 介绍,解释,说这个asynctask是吧任务放到一个队列里面,在后台由单独的线程或者有线程池来运行它,线程还是线程池要看版本,什么版本做的变化等等。 不做多的翻译了,主要想表达的就是这个解释能帮助我们理解源码,对我这样比较菜的是非常有帮助的,大佬直接能看懂的请忽略
接着往下走,来到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; exec.execute(mFuture); return this; }
private static class SerialExecutor implements Executor { final ArrayDeque它的内部有一个任务队列,串行执行,它是线程安全的,它主要负责将任务队列中的任务分发给执行线程池在执行,这个执行线程是在静态代码块中初始化的;以上是任务的分配,并且我们找到了AsyncTask第一个执行的方法 onPreExecute(),任务分配完以后,我们看看任务里面都做了什么,我们追溯mActive->mtasks->mfuture->mworkermTasks = new ArrayDeque (); 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); } } }
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; } };这里重写了call方法,相当于ruannable的run,在这个方法里我们看到了熟悉的 doInBackground( mParams ),mParams是作为worker的成员变量,已经在前边executeOnExecutor赋值,这里传入doInBackground(mParams) 这个方法里面,便于我们在重写doInBackground(mParams)的时候使用,这样,我们在execute里面穿的params就传到了doInBackground里面了,接着 doInBackground将结果返回给result,之后result在finally中的 postResult(result)中被hander机制用message传回主线程,什么?hander也要说下?那就点进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; }其中handler最终是用getMainHandler或者是传入mainLooper得到的主线程的handler,这次我们主要看AsyncTask哈,就不细说了,接下来看看发送的消息里面执行了啥,
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;
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }可以看出更新进度主要是往主线程发消息,传的参数就是我们想要的进度,正好DoInBackground里面有结果,在里面调用publishProgress,然后主线程里面的OnProgressUpdated就会被调用,在里面更新UI吧