• AsyncTask源代码解析


    快要毕业了。近期在阿里巴巴校园招聘面试,一面过了,感觉挺轻松,可能是运气好。面试官感觉比我腼腆一些。我俩从android绕到了spring mvc 到数据库悲观锁 到linux 然后又会到了android。这个面试收获挺大。多线程方面还得加强一下。但好在的是跟面试官谈了半个多小时源代码,可能这一点比較加分。继续准备二面。分析一些源代码吧





    public abstract class AsyncTask<Params, Progress, Result> {
        private static final String LOG_TAG = "AsyncTask";
    
    	//定义线程池的最小数量
        private static final int CORE_POOL_SIZE = 5;
    	//定义线程池的最大数量
        private static final int MAXIMUM_POOL_SIZE = 128;
    	//设置线程存活时间
        private static final int KEEP_ALIVE = 1;
    
    	//定义自己的线程创建project
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
    
            public Thread newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };
    
    	//定义一个线程工作队列。当超过十个线程的工作的时候会导致堵塞效果
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(10);
    
        //主要使用来运行任务
        public static final Executor THREAD_POOL_EXECUTOR
                = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    
        /**
         * An {@link Executor} that executes tasks one at a time in serial
         * order.  This serialization is global to a particular process.
         */
    	 //定义自己实现的一个Executor,在里面实现自己的一个ArrayDeque双端队列
        public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    
        private static final int MESSAGE_POST_RESULT = 0x1;
        private static final int MESSAGE_POST_PROGRESS = 0x2;
        //实现一个自己的handler
        private static final InternalHandler sHandler = new InternalHandler();
    
    	
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    	//实现了Callable的一个抽象类。在里面封装
        private final WorkerRunnable<Params, Result> mWorker;
    	//採用future模式运行任务
        private final FutureTask<Result> mFuture;
    
        private volatile Status mStatus = Status.PENDING;
        
        private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    
        private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            Runnable mActive;
    
    		//往队列里面提交runnable对象,然后调用scheduleNext去运行mActive , 开启一个线程,然后通过同步调用去运行一个runnable对象
            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);
                }
            }
        }
    
        /**
         * Indicates the current status of the task. Each status will be set only once
         * during the lifetime of a task.
         */
        public enum Status {
            /**
             * Indicates that the task has not been executed yet.
             */
            PENDING,
            /**
             * Indicates that the task is running.
             */
            RUNNING,
            /**
             * Indicates that {@link AsyncTask#onPostExecute} has finished.
             */
            FINISHED,
        }
    
        /** @hide Used to force static handler to be created. */
        public static void init() {
            sHandler.getLooper();
        }
    
    	//设置自己的一个Executor对象,否则就採用系统默认的
        /** @hide */
        public static void setDefaultExecutor(Executor exec) {
            sDefaultExecutor = exec;
        }
    	 //初始化一个AsyncTask对象
        public AsyncTask() {
    	//初始化一个Callable对象 实现call方法,而且设置mTaskInvoked为true 设置线程级别为后台线程
    	//然后去调用子类实现的doInBackground来完毕耗时操作,完毕之后在调用postResult来发送消息给自己定义的hadnler
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    return postResult(doInBackground(mParams));
                }
            };
    		
    		//实现自己的FutureTask done方法 当此任务转换到状态 isDone(无论是正常地还是通过取消)时,调用受保护的方法
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    try {
                        final Result result = get();
    
                        postResultIfNotInvoked(result);
                    } catch (InterruptedException e) {
                        android.util.Log.w(LOG_TAG, e);
                    } catch (ExecutionException e) {
                        throw new RuntimeException("An error occured while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    } catch (Throwable t) {
                        throw new RuntimeException("An error occured while executing "
                                + "doInBackground()", t);
                    }
                }
            };
        }
    
        private void postResultIfNotInvoked(Result result) {
            final boolean wasTaskInvoked = mTaskInvoked.get();
            if (!wasTaskInvoked) {
                postResult(result);
            }
        }
    
    	//把result通过handler发送出去
        private Result postResult(Result result) {
            Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }
    
        /**
         * Returns the current status of this task.
         *
         * @return The current status.
         */
        public final Status getStatus() {
            return mStatus;
        }
    
        /**
         * Override this method to perform a computation on a background thread. The
         * specified parameters are the parameters passed to {@link #execute}
         * by the caller of this task.
         *
         * This method can call {@link #publishProgress} to publish updates
         * on the UI thread.
         *
         * @param params The parameters of the task.
         *
         * @return A result, defined by the subclass of this task.
         *
         * @see #onPreExecute()
         * @see #onPostExecute
         * @see #publishProgress
         */
    	 //运行后台任务的方法
        protected abstract Result doInBackground(Params... params);
    
        /**
         * Runs on the UI thread before {@link #doInBackground}.
         *
         * @see #onPostExecute
         * @see #doInBackground
         */
    	 //在运行doInBackground之前调用的
        protected void onPreExecute() {
        }
    
        /**
         * <p>Runs on the UI thread after {@link #doInBackground}. The
         * specified result is the value returned by {@link #doInBackground}.</p>
         * 
         * <p>This method won't be invoked if the task was cancelled.</p>
         *
         * @param result The result of the operation computed by {@link #doInBackground}.
         *
         * @see #onPreExecute
         * @see #doInBackground
         * @see #onCancelled(Object) 
         */
        @SuppressWarnings({"UnusedDeclaration"})
        protected void onPostExecute(Result result) {
        }
    
        /**
         * Runs on the UI thread after {@link #publishProgress} is invoked.
         * The specified values are the values passed to {@link #publishProgress}.
         *
         * @param values The values indicating progress.
         *
         * @see #publishProgress
         * @see #doInBackground
         */
    	 //进度刷新时候调用。在这里能够进行ui更新
        @SuppressWarnings({"UnusedDeclaration"})
        protected void onProgressUpdate(Progress... values) {
        }
    
        /**
         * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
         * {@link #doInBackground(Object[])} has finished.</p>
         * 
         * <p>The default implementation simply invokes {@link #onCancelled()} and
         * ignores the result. If you write your own implementation, do not call
         * <code>super.onCancelled(result)</code>.</p>
         *
         * @param result The result, if any, computed in
         *               {@link #doInBackground(Object[])}, can be null
         * 
         * @see #cancel(boolean)
         * @see #isCancelled()
         */
        @SuppressWarnings({"UnusedParameters"})
        protected void onCancelled(Result result) {
            onCancelled();
        }    
        
        /**
         * <p>Applications should preferably override {@link #onCancelled(Object)}.
         * This method is invoked by the default implementation of
         * {@link #onCancelled(Object)}.</p>
         * 
         * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
         * {@link #doInBackground(Object[])} has finished.</p>
         *
         * @see #onCancelled(Object) 
         * @see #cancel(boolean)
         * @see #isCancelled()
         */
        protected void onCancelled() {
        }
    
        /**
         * Returns <tt>true</tt> if this task was cancelled before it completed
         * normally. If you are calling {@link #cancel(boolean)} on the task,
         * the value returned by this method should be checked periodically from
         * {@link #doInBackground(Object[])} to end the task as soon as possible.
         *
         * @return <tt>true</tt> if task was cancelled before it completed
         *
         * @see #cancel(boolean)
         */
        public final boolean isCancelled() {
            return mFuture.isCancelled();
        }
    
        /**
         * <p>Attempts to cancel execution of this task.  This attempt will
         * fail if the task has already completed, already been cancelled,
         * or could not be cancelled for some other reason. If successful,
         * and this task has not started when <tt>cancel</tt> is called,
         * this task should never run. If the task has already started,
         * then the <tt>mayInterruptIfRunning</tt> parameter determines
         * whether the thread executing this task should be interrupted in
         * an attempt to stop the task.</p>
         * 
         * <p>Calling this method will result in {@link #onCancelled(Object)} being
         * invoked on the UI thread after {@link #doInBackground(Object[])}
         * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
         * is never invoked. After invoking this method, you should check the
         * value returned by {@link #isCancelled()} periodically from
         * {@link #doInBackground(Object[])} to finish the task as early as
         * possible.</p>
         *
         * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
         *        task should be interrupted; otherwise, in-progress tasks are allowed
         *        to complete.
         *
         * @return <tt>false</tt> if the task could not be cancelled,
         *         typically because it has already completed normally;
         *         <tt>true</tt> otherwise
         *
         * @see #isCancelled()
         * @see #onCancelled(Object)
         */
        public final boolean cancel(boolean mayInterruptIfRunning) {
            return mFuture.cancel(mayInterruptIfRunning);
        }
    
        /**
         * Waits if necessary for the computation to complete, and then
         * retrieves its result.
         *
         * @return The computed result.
         *
         * @throws CancellationException If the computation was cancelled.
         * @throws ExecutionException If the computation threw an exception.
         * @throws InterruptedException If the current thread was interrupted
         *         while waiting.
         */
        public final Result get() throws InterruptedException, ExecutionException {
            return mFuture.get();
        }
    
        /**
         * Waits if necessary for at most the given time for the computation
         * to complete, and then retrieves its result.
         *
         * @param timeout Time to wait before cancelling the operation.
         * @param unit The time unit for the timeout.
         *
         * @return The computed result.
         *
         * @throws CancellationException If the computation was cancelled.
         * @throws ExecutionException If the computation threw an exception.
         * @throws InterruptedException If the current thread was interrupted
         *         while waiting.
         * @throws TimeoutException If the wait timed out.
         */
        public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
                ExecutionException, TimeoutException {
            return mFuture.get(timeout, unit);
        }
    
        /**
         * Executes the task with the specified parameters. The task returns
         * itself (this) so that the caller can keep a reference to it.
         * 
         * <p>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.  After
         * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, it is planned to change this
         * back to 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.
         *
         * <p>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}.
         */
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }
    
        /**
         * Executes the task with the specified parameters. The task returns
         * itself (this) so that the caller can keep a reference to it.
         * 
         * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
         * allow multiple tasks to run in parallel on a pool of threads managed by
         * AsyncTask, however you can also use your own {@link Executor} for custom
         * behavior.
         * 
         * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
         * a thread pool is generally <em>not</em> what one wants, because the order
         * of their operation is not defined.  For example, if these tasks are used
         * to modify any state in common (such as writing a file due to a button click),
         * there are no guarantees on the order of the modifications.
         * Without careful work it is possible in rare cases for the newer version
         * of the data to be over-written by an older one, leading to obscure data
         * loss and stability issues.  Such changes are best
         * executed in serial; to guarantee such work is serialized regardless of
         * platform version you can use this function with {@link #SERIAL_EXECUTOR}.
         *
         * <p>This method must be invoked on the UI thread.
         *
         * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
         *              convenient process-wide thread pool for tasks that are loosely coupled.
         * @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}.
         */
        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;
        }
    
        /**
         * Convenience version of {@link #execute(Object...)} for use with
         * a simple Runnable object.
         */
        public static void execute(Runnable runnable) {
            sDefaultExecutor.execute(runnable);
        }
    
        /**
         * This method can be invoked from {@link #doInBackground} to
         * publish updates on the UI thread while the background computation is
         * still running. Each call to this method will trigger the execution of
         * {@link #onProgressUpdate} on the UI thread.
         *
         * {@link #onProgressUpdate} will note be called if the task has been
         * canceled.
         *
         * @param values The progress values to update the UI with.
         *
         * @see #onProgressUpdate
         * @see #doInBackground
         */
        protected final void publishProgress(Progress... values) {
            if (!isCancelled()) {
                sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();
            }
        }
    
        private void finish(Result result) {
            if (isCancelled()) {
                onCancelled(result);
            } else {
                onPostExecute(result);
            }
            mStatus = Status.FINISHED;
        }
    
    	//定义自己的handler
        private static class InternalHandler extends Handler {
            @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;
                }
            }
        }
    
        private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
            Params[] mParams;
        }
    
        @SuppressWarnings({"RawUseOfParameterizedType"})
        private static class AsyncTaskResult<Data> {
            final AsyncTask mTask;
            final Data[] mData;
    
            AsyncTaskResult(AsyncTask task, Data... data) {
                mTask = task;
                mData = data;
            }
        }
    }

    以上是源代码大概一些方法的意思,关于AsyncTask的运行步骤例如以下

    1.当我们在new 自己的异步任务时候会初始化实例化两个类WorkerRunnable 。FutureTask,而且重写WorkerRunnable call方法和FutureTask的done方法。

    2.call方法主要运行子类复写的doInBackground,然后调用 postResult显示数据,在postResult里面去调用handler发送数据然后调用finish方法去调用子类的onPostExecute方法,这个时候我们就能够在自己复写的onPostExecute进行ui更新

    3.我们须要调用自己异步任务对象的execute方法。execute去调用executeOnExecutor方法在这种方法里面首先会调用onPreExecute();这种方法主要是在doInBackground。方法之前进行调用,做一些初始化工作的,有必要的时候就进行重写就可以,方法里面并没有不论什么代码。第二步会设置mWorker的mParams为我们调用execute时候传进来的參数,最后通过系统默认的Executor 去运行我们自己定义的FutureTask,从而运行WorkerRunnable call方法的代码。

    事实上感觉整个一个类的实现都很的简单,并不复杂

  • 相关阅读:
    nginx构建https
    安装mysql的遇到的问题
    docker mysql 2059
    centos7 安装chrome
    谷歌浏览器启动参数
    php-webdriver:PHP控制浏览器动作, php web驱动, PHP实现自动化, php webdriver 教程, A php client for webdriver.
    nginx转发
    nginx变量与实列
    mysql 语句
    frp 内网穿透配置
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/7237845.html
Copyright © 2020-2023  润新知