AsyncTask相信或多或少都使用过,其封装了线程池和handler,更优雅的处理了异步任务的交互,用起来也极为简单 本篇大概会涉及:
asynctask为何不能在主线程executeasynctask为何不能执行两遍executeasynctask的cancel如何停止一个正在执行的线程我们最常用的几个方法,在asynctask中何处被调用,如何被调用asynctask的整个执行逻辑 -简单使用:
private class MyAsyncTask extends AsyncTask<Void, Integer, Void> { @Override protected void onPreExecute() { mDialog.show(); } @Override protected Void doInBackground(Void... params) { for (int i = 0; i < 100; i++) { try { Thread.sleep(80); } catch (InterruptedException e) { e.printStackTrace(); } publishProgress(i); } return null; } @Override protected void onProgressUpdate(Integer... values) { mMyAsyncTask.cancel(true); mDialog.setProgress(values[0]); } @Override protected void onPostExecute(Void result) { mDialog.dismiss(); mTextView.setText("加载完毕"); //MyAsyncTask myAsyncTask = new MyAsyncTask(); 这里加上 就会循环执行 //myAsyncTask.execute(); } @Override protected void onCancelled() { Log.e(TAG, Thread.currentThread().getName() + " onCancelled "); } } MyAsyncTask myAsyncTask = new MyAsyncTask(); myAsyncTask.execute();使用注意:不可以在子线程调用myAsyncTask.execute();且同一个任务只可以执行一次(同一个任务指的是new MyAsyncTask())
太简单了,都不好意思说怎么用的,简单说下这泛型中的三个参数: Params, Progress, Result Params是doInBackground的参数类型,是execute执行时传递的参数类型 Progress 是onProgressUpdate的参数类型 Result 是onPostExecute任务结束返回的参数类型
———————-不华丽的风格陷——————————— 看源码解析吧: 我们基于myAsyncTask.execute();这行代码分析;
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { //必须是未执行的状态也就是创建asyncTask默认的状态 //如果是正在执行的任务或者是已经执行的任务都会直接抛出异常 //这里就验证了 一个执行中的任务不可以再次执行 //一个已经执行的任务(指的是new MyAsyncTask())不可以再次执行 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 通常我们会实现这个protected来做一些准备工作 //比如ui的更新 此时还是在主线程中 onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }那么 mWorker exec mFuture分别都是什么? mWorker:实现了Callable其call方法主要功能是调用doInBackground方法并获取结果,并将结果通过Handler切换到主线程 mFuture:实现了Runnable 其run方法会在子线程调用mWorker的call方法 exec:通过线程池执行mFuture 为什么没有展示一下他们的源码呢,下面会按流程分析到
看下exec,其传入的是一个默认sDefaultExecutor,最终来到这里 看下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.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }就是将一个runnable加入到队列中,这个r我们前面也说了就是mFuture下面的函数就是通过线程池执行这个runnable,好像没有什么逻辑这里,那么我们再去看下mFuture的run做了什么
public void run() { result = c.call(); if (ran) set(result); } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } if (s == INTERRUPTING) while (state == INTERRUPTING) Thread.yield(); // 释放占用的cpu资源 让给其他的任务 但放弃的时间不确定yield:释放占用的cpu资源 让给其他的任务 但放弃的时间不确定,这里不深究多线程的东西,继续走我们的主线 为了避免篇幅过长,我们只关注核心方法,首先调用了c.call();拿到了结果,那么我们肯定有个疑问,这个c是什么鬼?ok,我们看下c在哪里赋值的,
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } //asyncTask的构造函数中 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); } } };看到这里明白了,c是mWorker,那么我们知道了,真正获取结果还是在mWorker的call方法中啊,再去看一下,他的位置在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 result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } };看到一个属性的方法doInBackground,是不是突然觉得遇到熟悉的东西了..这里就调用我们自己的实现了,doInBackground(mParams)是运行在子线程的,这里我们模拟一下数据立即就返回了,那么会调用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; }这个应该也是非常熟悉的了,看到这个直接找handleMessage实现就稳了
@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; } }我们发送的是MESSAGE_POST_RESULT那么直接去看下finish就行,mTask也就是this
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }如果没有调用cancel那么直接调用onPostExecute了,ok这里我们一次任务执行差不多结束了,但是其mFuture的done还没有执行,可能有疑惑了,这哥们哪里调用的?
public void run() { result = c.call(); if (ran) set(result); }回到mFuture的run方法,在我们拿到数据后会调用 set(result); 在finishCompletion方法中我们可以看到 done();的调用
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); } } };回到done方法 看下他的实现做了啥呢?
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } }这里根据wasTaskInvoked判断是否调用postResult,但是在mWorker的call方法中我们已经将其置为true了,所以这里就GG了
走到这里我们认为其一次任务执行完毕,但是还有一个经常用到的publishProgress方法也要讲一下,这哥们怎么用的?
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }其也是运行在子线程的,这个消息我们上面也看到过
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; } }又遇到我们熟悉的onProgressUpdate方法了,我们经常在doInBackground执行耗时任务的同时通过publishProgress来触发onProgressUpdate来做ui更新,原来就是这样实现的啊…
还有个cancal方法需要讲一下 cancel(true);
public boolean cancel(boolean mayInterruptIfRunning) { if (!(state == NEW && U.compareAndSwapInt(this, STATE, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false; try { // in case call to interrupt throws exception if (mayInterruptIfRunning) { try { Thread t = runner; if (t != null) t.interrupt(); } finally { // final state U.putOrderedInt(this, STATE, INTERRUPTED); } } } finally { finishCompletion(); } return true; }t.interrupt();这里中断了线程的执行,call结束后通过handler处理时发现这个任务已经被取消 那么就会调用onCancelled 我们就可以通过实现onCancelled来完成一些ui交互 因为此时又在主线程了
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; } @SuppressWarnings({"UnusedParameters"}) protected void onCancelled(Result result) { onCancelled(); }经过我测试发现,就算调用了cancel,doInBackground中的任务还是会执行完,仅仅是不会调用onPostExecute罢了,而是走onCancelled,学过Java多线程的可能都知道通过interrupt来停止线程是停止不了的,需要辅以抛异常的方法,或者使用interrupted判断和retrun结合来停止线程,但是在run方法中貌似都没有这些,这里暂时我还没想到为什么停止了一个没有停止的线程有何意义,知道的烦请流个言,我是通过调用cancel辅以在doInBackground中catch捕获InterruptedException 异常直接返回的方式来结束线程运行,看下log验证
@Override protected void onProgressUpdate(Integer... values) { mMyAsyncTask.cancel(true); mDialog.setProgress(values[0]); } @Override protected Void doInBackground(Void... params) { for (int i = 0; i < 100; i++) { try { Thread.sleep(80); } catch (InterruptedException e) { Log.d(TAG, "InterruptedException : "); return null; } publishProgress(i); Log.d(TAG, "doInBackground : " + i); } Log.d(TAG, "doInBackground : 结束"); return null; }如果注释了return null;日志如下,很明显,虽然调用了cancel,他也确实调用了interrupt,但是其线程并没有停止
......... doInBackground : 91 doInBackground : 92 doInBackground : 93 doInBackground : 94 doInBackground : 95 doInBackground : 96 doInBackground : 97 doInBackground : 98 doInBackground : 99 doInBackground : 结束 main onCancelled如果解开return null的注释:很明显线程立即就停止执行并调用了onCancelled方法
doInBackground : 0 InterruptedException : main onCancelled总结:THREAD_POOL_EXECUTOR(线程池) Future Worker AsyncTask 1.线程池只负责执行runnable(Future), 2. 而Future则负责在子线程中调用Callable(Worker),并提供了一些其他操作方法,比如cancel方法,可以中断正在执行的线程 3.worker(Callable)只需要在call中接收doInBackground返回的结果即可, 4.AsyncTask统领全局,根据任务是否取消的状态来决定调用onPostExecute亦或onCancelled,当然AsyncTask还做了其他很多的工作, ——–四者分工明确
碎片时间文章不太工整,有错误的地方请指出