美文网首页
AsyncTask源码分析

AsyncTask源码分析

作者: 陈道乐 | 来源:发表于2020-01-30 13:24 被阅读0次

    使用

    提供了简单使用线程的方式,必须使用AsyncTask子类,然后调用execute执行任务即可。

    AsyncTask<Params, Progress, Result> {
        //在任务执行前调用,在UI线程中运行
        protected void onPreExecute() {
        }
        
        //抽象方法,在工作线程中执行
        protected abstract Result doInBackground(Params... params);
        
        //在UI线程中运行,在任务执行完成后,调用,并返回结果
        protected void onPostExecute(Result result) {
        }
        
        //在UI线程中运行,每次调用返回任务进度
        protected void onProgressUpdate(Progress... values) {
        }
        
        //用于提交任务进度,可以在doInBackground中调用
        protected final void publishProgress(Progress... values) {
            if (!isCancelled()) {
                getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();
            }
        }
    }
    

    源码分析

    主要采用 线程池 + handler 的机制, 看一下源码分析

    public abstract class AsyncTask<Params, Progress, Result> {
        private static final String LOG_TAG = "AsyncTask";
    
        //如果看过java 线程池实现的与源码,看到地下这几个参数,应该会很熟悉,这就是线程池子的基本参数
        
        //核心保留的线程数量就一个
        private static final int CORE_POOL_SIZE = 1;
        //运行中最大的线程数量
        private static final int MAXIMUM_POOL_SIZE = 20;
        
        //???
        private static final int BACKUP_POOL_SIZE = 5;
        
        //线程空闲之后的存活时间
        private static final int KEEP_ALIVE_SECONDS = 3;
        
        //这个工厂方法就是用来创建线程的
        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 ThreadPoolExecutor sBackupExecutor;
        
        //这是一个任务队列,存储一些,待执行的任务
        private static LinkedBlockingQueue<Runnable> sBackupExecutorQueue;
        
        //这是当任务不能被执行时,调用的处理方法
        private static final RejectedExecutionHandler sRunOnSerialPolicy =
                new RejectedExecutionHandler() {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
                // As a last ditch fallback, run it on an executor with an unbounded queue.
                // Create this executor lazily, hopefully almost never.
                synchronized (this) {
                    if (sBackupExecutor == null) {
                        //创建一个任务队列
                        sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
                        
                        //创建一个线程池,用于处理被拒绝的任务
                        sBackupExecutor = new ThreadPoolExecutor(
                                BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
                                TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
                       //核心线程不超时, 会一直运行,不会终止,即使没有任务
                       sBackupExecutor.allowCoreThreadTimeOut(true);
                    }
                }
                
                //执行任务
                sBackupExecutor.execute(r);
            }
        };
        
        //执行任务的(并行)线程池
        public static final Executor THREAD_POOL_EXECUTOR;
    
        static {
            //创建线程池
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(), sThreadFactory);
                    
            //设置一下,任务被拒绝的时候,调用的方法,就是我们上面的sRunOnSerialPolicy 这个东西
            threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
            THREAD_POOL_EXECUTOR = threadPoolExecutor;
        }
        
        //串行执行的线程池
        public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
        
        //来分析一下,串行线程池的实现
        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);
                }
            }
        }
        
        //这两个应该是消息post出去的code,用来标记的
        private static final int MESSAGE_POST_RESULT = 0x1;
        private static final int MESSAGE_POST_PROGRESS = 0x2;
        
        //默认使用的线程池是串行的
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        
        //这个是用于处理从子线程中抛出的数据
        private static InternalHandler sHandler;
    
        //很明了先直接继承了Handler类    
        private static class InternalHandler extends Handler {
            public InternalHandler(Looper looper) {
                super(looper);
            }
    
            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
            @Override
            public void handleMessage(Message msg) {
                //获取抛出的数据,到这里就是UI主线程了
                AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
                
                //开始分类处理不同的数据, 任务结果 或者是 任务进度
                switch (msg.what) {
                    case MESSAGE_POST_RESULT:
                        //调用AsyncTask的finihs接口表示任务结束了
                        result.mTask.finish(result.mData[0]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        //这里是进度的回调
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }
        
        //看一下抛到主线程的数据结构
        @SuppressWarnings({"RawUseOfParameterizedType"})
        private static class AsyncTaskResult<Data> {
            //包含两个成员变量,一个是任务实例的引用, 一个是抛出的数据
            final AsyncTask mTask;
            final Data[] mData;
    
            AsyncTaskResult(AsyncTask task, Data... data) {
                mTask = task;
                mData = data;
            }
        }
        
        //枚举变量,标识任务的状态
        public enum Status {
            /**
             * 指示任务还没执行
             */
            PENDING,
            /**
             * 指示任务开始运行
             */
            RUNNING,
            /**
             * 指示任务执行完成
             */
            FINISHED,
        }
        
        //看一下构造函数    
        public AsyncTask(@Nullable Looper callbackLooper) {
           //从这里可以看到,实际上如果没有指定特定线程的Loop, 使用的是主线程的Loop
            mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                ? getMainHandler()
                : new Handler(callbackLooper);
    
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
                    Result result = null;
                    try {
                    
                        //设置进程优先级,没看懂, 但是不影响接下来的阅读
                        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        
                        //执行一下,重载的任务代码
                        result = doInBackground(mParams);
                        
                        //这个也是看不明白,看资料这个代码有可能堵塞线程
                        Binder.flushPendingCommands();
                    } catch (Throwable tr) {
                        mCancelled.set(true);
                        throw tr;
                    } finally {
                        //将结果抛出
                        postResult(result);
                    }
                    return result;
                }
            };
    
            //创建一个Future处理一下相应的错误
            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);
                    }
                }
            };
        }
        
        //触发任务
         public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            //调用下面的方法executeOnExecutor
            return executeOnExecutor(sDefaultExecutor, params);
        }
    
        
        //这里算是比较核心的代码了,
        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;
        }
    }
    

    总结

    高并发的时候,不适合用,毕竟是串行执行的。串行的设计可以借用一下。

    相关文章

      网友评论

          本文标题:AsyncTask源码分析

          本文链接:https://www.haomeiwen.com/subject/gkpqzctx.html