AsyncTask 進(jìn)行耗時(shí)操作和UI 更新
相信各位對(duì) AsyncTask 不會(huì)陌生,雖然它有如下弊端:
1. 如果在activiy內(nèi)部new 一個(gè)AsyncTask, 橫豎屏切換生成一個(gè)新的activity,等結(jié)果返回時(shí),處理不好容易出現(xiàn)NPE。
2. 容易出現(xiàn)內(nèi)存泄漏,如果AsyncTask 進(jìn)行比較耗時(shí)的IO操作(網(wǎng)絡(luò)操作, 打開一個(gè)文件等等),在activity onDestroy的時(shí)候沒(méi)有cancel的話,
導(dǎo)致該Activity不能被GC回收(AsyncTask 在Activity內(nèi)部執(zhí)行耗時(shí)操作)。
3. 如果調(diào)用 executeOnExecutor, 如果等待queue里面的請(qǐng)求過(guò)多沒(méi)有得到及時(shí)處理,容易造成RejectException, 具體原因我在我的博客已經(jīng)有所介紹(AsyncTask RejectedExecutionException 小結(jié))。
閑話少說(shuō), 本文的重點(diǎn)不在于介紹AsyncTask的優(yōu)缺點(diǎn),而是一直有一個(gè)問(wèn)題困擾我,為什么AsyncTask 里面既能進(jìn)行UI 操作,又能進(jìn)行耗時(shí)的操作。
讓我們從代碼角度來(lái)分析這個(gè)問(wèn)題, 首先看他的構(gòu)造函數(shù):
public 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; } }; 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); } } }; }
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
public class FutureTask<V> implements RunnableFuture<V>
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
從上面的代碼可以看出, mWorker 實(shí)際上就是一個(gè) Callable, 而 mFuture 就是一個(gè)Thread, 構(gòu)造函數(shù)中將Callable 作為參數(shù)傳給了 FutureTask,下面
我們看看FutureTask 中的相關(guān)實(shí)現(xiàn):
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } 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); } }
protected void set(V v) { if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) { outcome = v; U.putOrderedInt(this, STATE, NORMAL); // final state finishCompletion(); } }
private void finishCompletion() { // assert state > COMPLETING; for (WaitNode q; (q = waiters) != null;) { if (U.compareAndSwapObject(this, WAITERS, q, null)) { for (;;) { Thread t = q.thread; if (t != null) { q.thread = null; LockSupport.unpark(t); } WaitNode next = q.next; if (next == null) break; q.next = null; // unlink to help gc q = next; } break; } } done(); callable = null; // to reduce footprint }
可以看到 result = c.call(); 在run方法中被調(diào)用, 實(shí)際就是 result = doInBackground(mParams); 被調(diào)用,因?yàn)樵摲椒ㄊ窃谧泳€程里面執(zhí)行,所以可以執(zhí)行耗時(shí)操作。 繼續(xù)讀代碼,call-> set(result) -> finishCompletion->done()-> postResultIfNotInvoked-> postResult
private Result postResult(Result result) { @SuppressWarnings("unchecked") 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() { super(Looper.getMainLooper()); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; switch (msg.wh所以at) { 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; } } }
相信上面的代碼大家都能看懂,值得說(shuō)明的是,因?yàn)?nbsp;InternalHandler的構(gòu)造函數(shù)使用 mainlooper,所以 handleMessage 當(dāng)然可以進(jìn)行UI 操作。
繼續(xù)看源碼:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
總結(jié)一下,虛函數(shù) doInBackground 在Thread(FutureTask)run方法執(zhí)行,所以能進(jìn)行耗時(shí)操作,而InternalHanlder 通過(guò)獲得mainlooper,在 handleMessage中調(diào)用 onPostExecute 從而保證了UI 操作可以在onPostExecute執(zhí)行。這個(gè)過(guò)程實(shí)際就是模板模式。

posted on 2017-04-25 17:34 布兜兜 閱讀(284) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)