AsyncTask 進行耗時操做和UI 更新

相信各位對 AsyncTask 不會陌生,雖然它有以下弊端:html

1. 若是在activiy內部new 一個AsyncTask, 橫豎屏切換生成一個新的activity,等結果返回時,處理很差容易出現NPE。android

2. 容易出現內存泄漏,若是AsyncTask 進行比較耗時的IO操做(網絡操做, 打開一個文件等等),在activity onDestroy的時候沒有cancel的話,網絡

致使該Activity不能被GC回收(AsyncTask 在Activity內部執行耗時操做)。less

3. 若是調用 executeOnExecutor, 若是等待queue裏面的請求過多沒有獲得及時處理,容易形成RejectException, 具體緣由我在個人博客已經有所介紹(AsyncTask RejectedExecutionException 小結)。ide

閒話少說, 本文的重點不在於介紹AsyncTask的優缺點,而是一直有一個問題困擾我,爲何AsyncTask 裏面既能進行UI 操做,又能進行耗時的操做。函數

讓咱們從代碼角度來分析這個問題, 首先看他的構造函數:oop

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 實際上就是一個  Callable, 而 mFuture 就是一個Thread, 構造函數中將Callable 做爲參數傳給了 FutureTask,下面post

咱們看看FutureTask 中的相關實現:this

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方法中被調用, 實際就是 result = doInBackground(mParams); 被調用,由於該方法是在子線程裏面執行,因此能夠執行耗時操做。 繼續讀代碼,call-> set(result) -> finishCompletion->done()-> postResultIfNotInvoked-> postResulturl

 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;
            }
        }
    }

相信上面的代碼你們都能看懂,值得說明的是,由於 InternalHandler的構造函數使用 mainlooper,因此 handleMessage 固然能夠進行UI 操做。

繼續看源碼:

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

總結一下,虛函數 doInBackground 在Thread(FutureTask)run方法執行,因此能進行耗時操做,而InternalHanlder 經過得到mainlooper,在 handleMessage中調用 onPostExecute 從而保證了UI 操做能夠在onPostExecute執行。這個過程實際就是模板模式。

 

相關文章
相關標籤/搜索