Android AsyncTask 源代码分析
AsyncTask源代码分析
public abstract class AsyncTask<Params, Progress, Result> {
    //日志TAG
    private static final String LOG_TAG = "AsyncTask";
    //池中所保存的线程数,包括空闲线程。
    private static final int CORE_POOL_SIZE = ;
    //池中允许的最大线程数。
    private static final int MAXIMUM_POOL_SIZE = ;
    //当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
    private static final int KEEP_ALIVE = ;
    //一个线程工厂,用来创建新线程 没啥好说的。
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        //这个类是一个线程安全的计数器,用到Unsafe直接与底层打交道。
        private final AtomicInteger mCount = new AtomicInteger();
        //接口实现的方法,就是给线程起了个名字。
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };
    //一个固定长度的LinkedBlockingQueue(队列),长度为10。
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>();
    //一个线程池,关于这个类的细节可以单独研究,这里不细说,就跟连接池的思想一样
    //里面维护着一些线程 可以同时处理一些任务。
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    //创建一个实现了Executor接口的类 这个类的介绍在下面
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    //Message的消息类型
    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;
    //通知主线程的Handler,细节在下面有解释
    private static final InternalHandler sHandler = new InternalHandler();
    //就是把上面的SERIAL_EXECUTOR拿过来了,和上面的一样
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //实现了Callable接口 添加了一个参数Params
    private final WorkerRunnable<Params, Result> mWorker;
    //封装具体的任务,这个类的细节可以单独研究 这里也不做细说。
    //这个类的特点就是可以取消并且可以监控任务状态
    private final FutureTask<Result> mFuture;
    //将状态设置成【还没开始执行】的状态
    private volatile Status mStatus = Status.PENDING;
    //标记任务是否已经取消,后面的一些方法需要用到。
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    //标记任务是否已经执行,后面的一些方法需要用到。
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    //实现Executor接口 对Runnable(任务)在进行一次封装
    //这样的实现可以使任务保持连续,即第一个任务执行完毕接着会执行第二个任务
    //第二个任务执行在执行第三个任务,以此类推。
    private static class SerialExecutor implements Executor {
        //一个数组双端队列没有容量限制
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        //当前正在执行的任务
        Runnable mActive;
        //这里进行了synchronized,因为ArrayDeque不是线程安全的,对它的操作需要同步。
        public synchronized void execute(final Runnable r) {
            //对任务进行包装,然后加入队列的末尾。
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        //执行具体任务
                        r.run();
                    } finally {
                        //执行下一个任务【编号001】
                        scheduleNext();
                    }
                }
            });
            //如果当前没有执行的任务,则调用scheduleNext开始执行任务
            //如果不为null 说明已经有任务在执行,那么就不需要调用scheduleNext
            //因为当前任务会被上一个任务在完成时调用。即在【编号001】的位置。
            if (mActive == null) {
                scheduleNext();
            }
        }
        //从队列的头部拿出一个元素,然后执行。这里的任务是在上面包装过的。
        //它会先执行具体任务,然后再执行下一个任务
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    //当前类的状态
    public enum Status {
        //还没开始执行
        PENDING,
        //执行中
        RUNNING,
        //任务完成
        FINISHED,
    }
    //没啥用
    public static void init() {
        sHandler.getLooper();
    }
    //没啥用
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }
    //构造参数必须运行在UI线程
    public AsyncTask() {
        //创建一个WorkerRunnable实例
        //这里用到了FutureTask与Callable相关技术。需要自己去研究下
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                //一旦具体任务执行,就将这个标记置为true
                mTaskInvoked.set(true);//【编号002】
                //设置当前线程优先级为后台线程
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //首先调用doInBackground这个方法 就是我们需要复写的方法。
                //然后调用postResult方法 并将doInBackground的返回值传入。
                return postResult(doInBackground(mParams));
            }
        };
        //创建一个任务FutureTask,并将上面的mWorker通过构造参数传入。
        mFuture = new FutureTask<Result>(mWorker) {
            //覆写了done方法,这样当任务的状态发生变化时可以进行监控。
            //当任务完成时或取消都进入该方法
            @Override
            protected void done() {
                try {
                    //通过get方法获取任务的返回结果
                    //下面就分2中情况
                    //1-如果上面的call方法正确被调用 那么就执行postResultIfNotInvoked方法
                    //2-如果任务被取消或者任务执行过程中出现异常则会抛出异常,在下面catch到在进行处理
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    //如果在doInBackground方法中存在异常 这里会继续抛出
                    throw new RuntimeException("An error occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    //如果方法被取消,那么调用postResultIfNotInvoked并传入null
                    postResultIfNotInvoked(null);
                }
            }
        };
    }
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        //这里判断wasTaskInvoked标记,判断任务是否已经正常结束
        //如果在mWorker的call方法正确执行 那么在【编号002】的位置会把wasTaskInvoked设置为true
        //这样的话在done()方法中的postResultIfNotInvoked(get());方法才不会重复执行
        //也就是说方法如果在mWorker的call方法中执行了 那么在done()中在调用postResultIfNotInvoked(get());
        //方法在执行到这的话就不会执行了,反之亦然。
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }
    //该方法是把任务结果发送给UI线程去执行
    //就是Looper Handler Message 没啥好说的
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    //过去当前任务的执行状态
    public final Status getStatus() {
        return mStatus;
    }
    //需要子类付覆写的方法,后台线程运行。
    protected abstract Result doInBackground(Params... params);
    //在doInBackground方法执行运行,UI线程运行该方法。
    //可以启动个进度条之类的操作可以写在这里。
    protected void onPreExecute() {
    }
    //UI线程执行,在doInBackground放执行以后执行。
    //要注意的是在任务没有出现异常 也没有被取消的情况下才会执行
    //否则执行onCancelled
    @SuppressWarnings({"UnusedDeclaration"})
    protected void onPostExecute(Result result) {
    }
    //运行在UI线程 通过在doInBackground中调用publishProgress方法通知UI线程做一些处理
    //比如更新带百分比的进度条等
    @SuppressWarnings({"UnusedDeclaration"})
    protected void onProgressUpdate(Progress... values) {
    }
    @SuppressWarnings({"UnusedParameters"})
    protected void onCancelled(Result result) {
        onCancelled();
    }    
    //一般子类覆写这个方法 就是cancel方法被调用后 任务被取消 则会执行该方法
    protected void onCancelled() {
    }
    //获取任务是否取消
    public final boolean isCancelled() {
        return mCancelled.get();
    }
    //终止任务
    //参数的意义是这样的
    //如果线程还没有被启动,那么无论mayInterruptIfRunning是啥 任务都会被取消
    //如果任务已经启动 那么如果mayInterruptIfRunning=true 那么会调用线程的
    //interrupt方法,这个方法是的解释可以看API 太多了 这里不细说。
    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }
    //这个方法获取任务的结果,是一个阻塞方法
    //属于FutureTask的范畴
    public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }
    //同上
    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        return mFuture.get(timeout, unit);
    }
    //启动任务
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        //调用executeOnExecutor
        return executeOnExecutor(sDefaultExecutor, params);
    }
    //这个方法是AsyncTask的启动方法,用来启动任务
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        //判断任务的状态 如果不是PENDING状态则抛出异常
        //也就是说任务只能启动一次,不可重复启动。
        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)");
            }
        }
        //设置任务状态为RUNNING
        mStatus = Status.RUNNING;
        //调用预处理方法上面解释过。
        onPreExecute();
        //给mWorker设置参数
        mWorker.mParams = params;
        //将任务加入到sDefaultExecutor当中去执行
        exec.execute(mFuture);
        //返回自己
        return this;
    }
    //这个方法是用过sDefaultExecutor执行直接执行一个Runnable接口,去AsyncTask没啥关系
    //无非就是用到了sDefaultExecutor
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }
    //这个方法可以通知UI线程更新进度
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
    //任务完成后调用的方法,会根据isCancelled()的返回值判断任务是否被取消或者正常执行成功。
    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[]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
    //一个抽象类实现了Callable<Result>接口 添加了参数。
    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 核心原理大概如下
InternalHandler sHandler = new InternalHandler(); 这个handler是主线程初始化的,用来调用更新UI的方法。
THREAD_POOL_EXECUTOR 一个线程池用来处理异步任务。
sPoolWorkQueue 一个任务队列,我们发起的所有任务都会放到这个队列当中,由THREAD_POOL_EXECUTOR 它来进行处理。
流程就是当我们创建一个AsyncTask实例 ,那么AsyncTask会生成一个任务对象(Runnable)放入sPoolWorkQueue 这个队列当中,然后有THREAD_POOL_EXECUTOR 线程池去进行异步处理,在处理的过程中通过sHandler 通知主线程去调用我们复写的那几个方法更新UI。
这个类在设计当中还使用到了 FutureTask
关于这个类的源码分析请看我的另外一个博客:http://www.cnblogs.com/daxin/p/3802392.html
Android AsyncTask 源代码分析的更多相关文章
- Android异步任务处理框架AsyncTask源代码分析
		
[转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 引言 在平时项目开发中难免会遇到异步耗时的任务(比方最常见的网络请求).遇到这样的问题.我 ...
 - Android 消息处理源代码分析(1)
		
Android 消息处理源代码分析(1) 在Android中,通常被使用的消息队列的代码在文件夹\sources\android-22\android\os下,涉及到下面几个类文件 Handler.j ...
 - Android  HandlerThread  源代码分析
		
HandlerThread 简单介绍: 我们知道Thread线程是一次性消费品,当Thread线程运行完一个耗时的任务之后.线程就会被自己主动销毁了.假设此时我又有一 个耗时任务须要运行,我们不得不又 ...
 - Android HttpURLConnection源代码分析
		
Android HttpURLConnection源代码分析 之前写过HttpURLConnection与HttpClient的差别及选择.后来又分析了Volley的源代码. 近期又遇到了问题,想在V ...
 - Android KLog源代码分析
		
Android KLog源代码分析 Android KLog源代码分析 代码结构 详细分析 BaseLog FileLog JsonLog XmlLog 核心文件KLogjava分析 遇到的问题 一直 ...
 - android开发源代码分析--多个activity调用多个jni库的方法
		
android开发源代码分析--多个activity调用多个jni库的方法 有时候,我们在开发android项目时会遇到须要调用多个native c/jni库文件,下面是本人以前实现过的方法,假设有知 ...
 - Android 消息处理源代码分析(2)
		
Android 消息处理源代码分析(1)点击打开链接 继续接着分析剩下的类文件 Looper.java public final class Looper { final MessageQueue m ...
 - Appium Android Bootstrap源代码分析之启动执行
		
通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...
 - Android `AsyncTask`简要分析
		
AsyncTask简要分析 经典异步任务:AsyncTask,使用场景有:批量下载,批量拷贝等.官方文档就直接给出了一个批量下载的示例. private class DownloadFilesTask ...
 
随机推荐
- JAVA常见异常解析
			
1. java.lang.nullpointerexception 这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的对 ...
 - 使用自定义模板来弥补eclipse没有新建Filter的功能
			
http://yufei.iteye.com/blog/125012 eclipse插件,并没有为我们提供Filter的新建功能,为此我们不得不每次都去新建个类,然后输入那繁琐的重复代码,这完全就是浪 ...
 - 通过iscsi协议使用ceph rbd
			
转自:http://blog.csdn.net/wytdahu/article/details/46545235 ceph很早就已经支持通过iscsi协议来使用rbd,这篇博文对此做下演示,并且使用O ...
 - C#基础 - C# 的 常见概念简述
			
在上篇文章中,你跟着我写了一个HelloWorld,本篇中,我们来谈谈一些C#程序中的小概念 1.C# 程序结构 一个 C# 程序主要包括以下部分: 命名空间声明(Namespace declarat ...
 - 关于FSMC地址线的理解
			
http://www.openedv.com/thread-33759-1-1.html (出处: OpenEdv-开源电子网)
 - python标准库介绍——11     atexit  模块详解
			
=== atexit 模块=== (用于2.0版本及以上) ``atexit`` 模块允许你注册一个或多个终止函数(暂且这么叫), 这些函数将在解释器终止前被自动调用. 调用 ``register`` ...
 - 为什么easyui的datagrid里getSelections还有getChecked只能获取一行值呢?
			
http://jquery-easyui.wikidot.com/forum/t-280470 如果没有 idField属性,getSelections就只能获取一个行的值了 注意:如果用了前面说的& ...
 - Racket 版本的 24 点实现
			
Racket 版本的 24 点实现 #lang racket ; Author: woodfox ; Date: Oct 11, 2014 ; ==================== 1. Non- ...
 - [na]非对称加密方式&带加密的数字签名交互流程
			
1,对称加密 2,混合加密 3.数字签名 4,带加密的数字签名
 - 【Android】8.1 主题基本用法
			
分类:C#.Android.VS2015: 创建日期:2016-02-17 一.创建本章示例主界面 1.界面截图 2.MainActivity.cs文件中对应的代码 在CreateChItems()方 ...