• AsyncTask 进行耗时操作和UI 更新


    相信各位对 AsyncTask 不会陌生,虽然它有如下弊端:

    1. 如果在activiy内部new 一个AsyncTask, 横竖屏切换生成一个新的activity,等结果返回时,处理不好容易出现NPE。

    2. 容易出现内存泄漏,如果AsyncTask 进行比较耗时的IO操作(网络操作, 打开一个文件等等),在activity onDestroy的时候没有cancel的话,

    导致该Activity不能被GC回收(AsyncTask 在Activity内部执行耗时操作)。

    3. 如果调用 executeOnExecutor, 如果等待queue里面的请求过多没有得到及时处理,容易造成RejectException, 具体原因我在我的博客已经有所介绍(AsyncTask RejectedExecutionException 小结)。

    闲话少说, 本文的重点不在于介绍AsyncTask的优缺点,而是一直有一个问题困扰我,为什么AsyncTask 里面既能进行UI 操作,又能进行耗时的操作。

    让我们从代码角度来分析这个问题, 首先看他的构造函数:

    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,下面

    我们看看FutureTask 中的相关实现:

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

    相信上面的代码大家都能看懂,值得说明的是,因为 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执行。这个过程实际就是模板模式。

  • 相关阅读:
    WCF开发笔记 高版本.Net的坑
    Net Start可以加载驱动
    解决:Windows 2008远程黑屏问题
    Visual Studio 解决方案版本从v12-->v14
    Visual Studio 使用之禁用/启用模板警告
    Windows 10 常用的快捷键及常用指令
    git
    Socket通信原理 很好
    java集合
    JavaEE简介
  • 原文地址:https://www.cnblogs.com/budoudou/p/6763357.html
Copyright © 2020-2023  润新知