AsyncTask原理和源码解析

0、目录

一、简介

二、使用方法以可能存在的问题

三、工作原理

四、类和核心方法的介绍

         4.1、类定义

         2.2、核心方法

五、源码分析

六、总结

一、简介

二、使用方法以及可能存在的问题

使用方法请详见《AsyncTask使用详细介绍(含使用实例)

可能存在的问题详见《AsyncTask存在的问题和缺陷

三、工作原理

AsyncTask的实现原理:线程池+Handler

1、内部实现创建工作线程,并使用线程池实现线程的调度和复用

2、内部实现Handler用于异步通信,实现更新UI

因为,每次使用时,无论创建工作线程,还是实现异步通信,都是固定的模式,且都要实现一遍,显然是很麻烦的,所以系统内部抽象出了AsyncTask类,使我们不用再关注创建工作线程和异步通信,而是重点关注业务的实现。

内部实现了两个线程池和一个Handler.

四、类和核心方法的介绍

4.1、类定义

public abstract class AsyncTask<Params, Progress, Result> {
 	......
}

1、首先AsyncTask是抽象类,所以不可直接实例化,必须实现子类。

2、 AsyncTask<Params, Progress, Result>使用泛型,主要作用是在执行任务控制输入或返回的数据类型。

      Params:决定了执行excute()方法时传入的参数类型,excute()方法传入的参数会传入到方法doInBackground(),所以同时也决定了doInBackground()方法内的参数类型。

     Progress:任务执行时,返回进度值的类型,即onProgressUpdate()方法内的参数类型。

     Result:任务完成后,返回的结果的类型,即doInBackground()方法的返回类型,doInBackground()方法的返回结果传入onPostExecute()方法作为参数,所以同时也决定了onPostExecute()方法的参数类型。

注:Params, Progress, Result并不一定都要使用,如果没有使用,可以用java.lang.Void代替。

2.2、核心方法

切记自己不能手动调用onPreExecute(), doInBackground(), onProgressUpdate(),onPostExecute(),onCancelled()等方法,这些方法都是系统自动调用的。

五、源码分析

AsyncTask的使用可以分为三步:

步骤一:继承AsyncTask,创建AsyncTask的子类,并根据需要复写相关方法

步骤二:创建AsyncTask子类的实例对象

步骤三:调用该子类实例对象的execute()方法,执行异步任务

具体如下:

//步骤1、创建AsyncTask的子类,并根据需要复写相关方法
//继承AsyncTask,并确定泛型类型
class mAsyncTask extends AsyncTask<String, Integer, String> {
        //UI线程执行
        //任务执行前的准备工作
        @Override
        protected void onPreExecute() {
           
        }
 
        //必须复写,因其在AsyncTask内是抽象函数
        //异步任务真正执行的位置
        @Override
        protected String doInBackground(String... strings) {
              //子线程中执行
              //可调用publidshProgress(Integer)方法触发onProgressUpdate()方法执行,更新进度
              return null;
        }
 
        //UI线程执行
        //更新线程任务进度
        @Override
        protected void onProgressUpdate(Integer... values) {
             
        }
 
        //UI线程执行
        //异步任务执行完成后的一些操作
        @Override
        protected void onPostExecute(String s) {
            
        }
 
        //UI线程执行
        //异步任务被取消时调用
        @Override
        protected void onCancelled(String s) {
             
        }
}
//步骤2、创建AsyncTask的子类实例对象
    //UI线程中执行
    mAsyncTask task = new mAsyncTask();
//步骤3、调用子类实例对象的execute()方法,执行异步任务
    //UI线程中手动调用execute(Params... params)方法,系统会自动调用步骤一中的各种方法
    //同一个实例对象只能执行一次,否则会抛出异常
    task.execute(); 

接下来,根据具体使用过程中的三个步骤,分别依次分析源码

步骤一:继承AsyncTask,创建AsyncTask的子类,并根据需要复写相关方法

      复写的方法将会在后面调用

步骤2、创建AsyncTask的子类实例对象

     mAsyncTask task = new mAsyncTask();

//构造函数
 public AsyncTask() {
        //即调用 AsyncTask(Looper callbackLooper) 
        this((Looper) null);
    } 

public AsyncTask(@Nullable Looper callbackLooper) {
        //1、判断参数callbackLooper是否为空或为主线程的Looper,
        //若是则获取主线程Handler,否则根据callbackLooper创建新的Handler
        //getMainHandler() -->>分析1
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        //2、初始化一个WorkerRunnable -->>分析5
        mWorker = new WorkerRunnable<Params, Result>() {
            //实现了call()方法,在调用execute()方法时调用
            //类似于Runnable中的run()方法,
            public Result call() throws Exception {
                //已经在工作线程中执行
                //添加线程任务的一个标志
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    //设置线程优先级
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //调用步骤一中复写的doInBackground()方法,即执行的异步耗时操作
                     //mParams是在执行execute()方法时传入的参数
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    //最后把异步任务执行的结果传到主线程,更新UI -->>分析6
                    postResult(result);
                }
                return result;
            }
        };

        //创建一个FutureTask,来执行mWorker  -->>分析7
        mFuture = new FutureTask<Result>(mWorker) {
            //invoked when this task transitions to state isDone (whether normally or via cancellation)
            //当FutureTask内的(mWorker内的)Callable被执行完成后被调用
            //作用是检查任务的调用,将未被调用的任务的结果传递到主线程
            @Override
            protected void done() {
                try {
                    //-->>分析8
                    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);
                }
            }
        };
    }

分析1:getMainHandler()
    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                 //如果sHandler为空,则根据主线程的Looper创建一个InternalHandler对象实例
                 //即InternalHandler类型的sHandler绑定到了主线程的Looper  -->>分析2
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

//分析2:InternalHandler
    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        //复写handleMessage()
        //已经是在UI线程执行
        @Override
        public void handleMessage(Message msg) {
            //传过来的Message的obj对象是AsyncTaskResult<?>类型
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                  //MESSAGE_POST_RESULT表示传递过来的是resulet
                 //数据是在postResult(Result result)方法内传递过来的
                case MESSAGE_POST_RESULT:
                    // 如果传递来的是结果 -->>分析3
                    result.mTask.finish(result.mData[0]);
                    break;
                //MESSAGE_POST_PROGRESS表示传递过来的数据是执行任务的进度值
                //数据在publishProgress(Progress... values)方法内传递过来的
                case MESSAGE_POST_PROGRESS:
                    // 如果传递来的是执行任务的进度值  -->>分析4 
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
分析3:result.mTask.finish(result.mData[0]);
    result 是AsyncTaskResult<?> 类型的,定义如下:
    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

    result.mTask是AsyncTask 类型的,其finish()方法定义如下:
    private void finish(Result result) {
        //isCancelled():Returns true if this task was cancelled before it completed normally
        if (isCancelled()) {
            //执行异步任务过程中点击取消,则调用步骤一中复写的onCancelled()方法
            onCancelled(result);
        } else {
            //否则调用步骤一中复写的onPostExecute()方法
            onPostExecute(result);
        }
        //状态标记为完成
        mStatus = Status.FINISHED;
    }

分析4:result.mTask.onProgressUpdate(result.mData);
    即调用步骤一中复写的onProgressUpdate()方法

分析5:WorkerRunnable 
  private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }
    抽象类WorkerRunnable继承了Callable,且有一变量mParams,该变量在调用execute()方法时用于表示传入的参数。

分析6:postResult(result)
     private Result postResult(Result result) { 
        //getHandler即是分析1中返回的sHandler 
        //obtainMessage (int what, Object obj),即what是MESSAGE_POST_RESULT;
        //obj是new AsyncTaskResult<Result>(this, result)
        //obtainMessage ()中,还把getHandler()中获得的sHandler赋制给了Message的Target属性
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        //即把Message对象发给了getHandler()中获得的sHandler,之后由分析3处理
        message.sendToTarget();
        return result;
    }
 
分析7:FutureTask
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    callable类似于Runnable,执行FutureTask的对象实例时,callable内的call()方法将被执行

分析8:postResultIfNotInvoked
    private void postResultIfNotInvoked(Result result) {
        //获得线程的状态
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            //传递结果到主线程,详见分析6
            postResult(result);
        }
    }

总结:

1、获得InternalHandler 类型的Handler,用于异步消息的处理

2、创建了一个WorkerRunnable类实例对象mWork,并复写了call()方法,call()方法内的代码已经是在工作线程中执行

3、创建了一个FutureTask类实例对象mFuture,并复写了done()方法

4、通过分析可以看到,在步骤一中复写的一些方法已经被使用

步骤3、调用子类实例对象的execute()方法,执行异步任务

 执行代码:
    task.execute(); 

//源码分析:
 public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        //sDefaultExecutor是一个SerialExecutor类型线程池 -->>分析1
        //executeOnExecutor() -->>分析4
        return executeOnExecutor(sDefaultExecutor, params);
    }

分析1:线程池SerialExecutor 
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    线程池SerialExecutor源码如下:
    private static class SerialExecutor implements Executor {
        //static :说明这是一个静态内部类
        //存放Runnable类型元素的双向队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        //该方法被synchronized关键字修饰
        //表示多个线程同时执行时只有一个线程能进入该方法
        //具体调用位置是在executeOnExecutor()方法内的exec.execute(mFuture)
        //mFuture-->mWorker-->call()
        public synchronized void execute(final Runnable r) {
            //把Runnable类对象添加到mTasks队列
            //把异步任务和取出下一个任务并执行作为一个Runnable对象放到队列mTasks
            //目的是为了一个任务执行完成后,能自动执行下一个任务
            //从这里能够看出异步任务的执行时串行的,即执行完一个任务后再执行下一个任务
            mTasks.offer(new Runnable() { 
                public void run() {
                    try {
                        r.run();
                    } finally {
                        //执行完一个异步任务后自动从队列取出下一个任务并执行 -->>分析2
                        scheduleNext();
                    }
                }
            });
            //添加队列后,判断当前是否有任务正在执行,若没有,从队列取出任务并执行
            //一般在添加第一个任务到队列时使用,即添加第一个任务后,取出第一个任务并执行
            if (mActive == null) {
                scheduleNext();
            }
        }

        //从mTasks队列取出下一个任务并执行
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

分析2:scheduleNext()
    //从队列中取出一个任务并执行
    protected synchronized void scheduleNext() {
            //从队列mTasks中取出一个任务
            if ((mActive = mTasks.poll()) != null) {
                //调用线程池THREAD_POOL_EXECUTOR执行该任务
                // -->>分析3
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

分析3:线程池THREAD_POOL_EXECUTOR相关的源码
    //CPU的数量  Returns the number of processors available to the JVM.
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    //线程池的核心线程数量,数量在2--4之间
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    //线程池最大线程数量
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    //线程池中空闲线程保存存活时间
    private static final int KEEP_ALIVE_SECONDS = 30;
    //初始化线程工程
    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());
        }
    };
    //创建存放Runnable类型的任务队列,且最多存放128个
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }
通过线程池THREAD_POOL_EXECUTOR 的创建,可以看到它是可以并行执行的,只是在实际使用中,执行完一个异步任务后再取出下一个交由线程池THREAD_POOL_EXECUTOR 去处理,所以最后任务的执行依然是串行的。

分析4:executeOnExecutor()
    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()
        onPreExecute();
        //execute()传入的参数赋值,以便在mWorker中使用
        mWorker.mParams = params;
        //执行异步任务  exec就是线程池SerialExecutor的实例对象,详见分析1
        exec.execute(mFuture);

        return this;
    }

总结:

1、异步任务执行时,通过SerialExecutor类型线程池把所有的线程顺序放到一个队列中

2、然后再从这个队列中取出任务,由线程池THREAD_POOL_EXECUTOR执行异步任务,执行完一个任务后再从队列中取出下一个任务并执行,任务是串行执行的。

如想异步任务并行执行,在主线程调用AsyncTask的executeOnExecutor (Executor exec, Params... params)方法,其中第一个参数为AsyncTask.THREAD_POOL_EXECUTOR。

取消异步线程任务

执行:task.cancel(true);

    //源码:
    //即便是取消任务,实际并没有真正取消,异步任务依然会执行,直到结束
    //只是任务结束后,不会再调用onPostExecute()方法,而是调用onCancelled()方法
   public final boolean cancel(boolean mayInterruptIfRunning) {
        //设置任务是否被取消标志
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

六、总结

最后做一个简单的总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值