从源码分析AsyncTask

AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。
主要有4个核心方法,它们的含义如下所示。

  1. onPreExecute():在主线程中执行,在异步任务执行之前,此方法会被调用,一般用于做一些准备工作。
  2. doInBackground(Params…params):在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务进度,publishProgress方法会调用onProgressUpdate方法。另外此方法需要返回计算结果给onPostExecute方法。
  3. onProgressUpdate(Progress…Values):在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。
  4. onPostExecute(Result result):在主线程中执行,在异步任务执行以后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。

AsyncTask在具体的使用过程中也是有一定条件限制的,主要有如下几点:

  1. AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android4.1及以上版本中已经被系统自动完成。在Android5.0的源码中,可以查看ActivityThread的main方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件了。
  2. AsyncTask的对象必须在主线程中创建。
  3. execute方法必须在UI线程中调用。
  4. 不要在程序中直接调用onPreExecute、onPostExecute、doInBackground和onProgressUpdate方法。
  5. 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
    AsyncTask是串行执行任务的,但是可以通过executeOnExecutor方法来并行地执行任务。

AsyncTask其实本质上是有2个线程池(SerialExecutor:用于任务的排序;THREAD_POOL_EXECUTOR:真正执行任务)和handler组成,下面来分析一下源码。

源码分析

为了分析AsyncTask的工作原理,我们从它的execute方法开始分析,execute方法又会调用executeOnExecutor方法,它们的实现如下所示。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        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中的任务主要有三种状态PENDING、RUNNING、FINISHED,可以看到,只有当任务为PENDING的时候才会继续运行,并且直接转为RUNNING,通过后面的源码,还能看到当任务完成以后,会转成FINISHED,这就解释了第五点条件限制(为什么一个AsyncTask对象只能执行一次)
继续往下看,onPreExecute()即我们上面提到的第一个核心方法,它是直接在源码中调用的,不需要我们写程序调用。 然后是mWorker.mParams = params exec.execute(mFuture),这里出现了2个没提到过的mWorker和mFuture,我们得先知道这两个东西是什么。
首先是mWorker

     private final WorkerRunnable<Params, Result> mWorker;
     
     private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
          Params[] mParams;
      }
      
    public interface Callable<V> {
        V call() throws Exception;
    }

好了,线索断了,我们得去找调用它的地方了。发现是在AsyncTask的构造函数中

public AsyncTask(@Nullable Looper callbackLooper) {
        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);
                    //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);
                }
            }
        };
    }

这个构造函数可以分成三块,mHandler、mWorker、mFuture的实例化,其他先不管,我们先看mWorker。
首先先看try块中的代码

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);	//设置子线程优先执行
result = doInBackground(mParams);

这里出现了第二个核心代码 doInBackground,发现其是一个抽象函数,需要我们自己实现

protected abstract Result doInBackground(Params... params);

然后是finally代码块中的postResult(result) ,其相关代码是

private Result postResult(Result result) {
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

这里就很眼熟了,我这里将相关代码都贴出来,一起分析

    1、private Handler getHandler() {
            return mHandler;
        }


    2、mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                        ? getMainHandler()
                        : new Handler(callbackLooper);


    3、private static Handler getMainHandler() {
            synchronized (AsyncTask.class) {
                if (sHandler == null) {
                    sHandler = new InternalHandler(Looper.getMainLooper());
                }
                return sHandler;
            }
        }
       

     4、private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
        @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;
            }
        }
    }

    5、private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
  
    6、private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

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

我这里贴了5个地方的代码,一个个来看,主要就是为了解释这个handler是处在什么线程中。
第一块就是返回一个handler,没什么好说的。
第二块是上面AsyncTask的构造函数中的代码,是一个三元运算符,也很好理解。
第三、四则是实例化了这个handler,并且重写了handleMessage方法。
第五块则是该AsyncTask的finish方法(首先判断当前的asynctask是否被取消,若果没取消则执行onPostExecute(result),这个第四个核心代码,这时候数据已经回调了,到这里我们就差不多执行完了几个重要的方法了,然后再将asynctask的执行状态切换到FINISHED状态。)
第六块则是把当前从网络下请求的结果数据result保存到data中。然后通过message.sendToTarget,就是通过handler把message发送出去。这里不理解的可以先去补一下消息队列的原理。
至此,mWorker就分析完毕了,总结来说,mWorker中主要存储了我们重写的doInBackground方法,即需要在线程池中运行的代码。然后通过handler发送出去。
然后是mFuture,它是继承自FutureTask,并将mWorker作参数,FutureTask代码有点多,主要就是在其done()中会调用mWorker的call()方法。在done()中还调用了postResultIfNotInvoked方法。

private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
其实在mWorker的构造方法中,我们已经mTaskInvoked.set(true);
所以这里的postResult(result)一般执行不到。
OK,我们差不多大致了解了mWorker、mFuture大概是怎么用的,我们就可以继续看最上面的executeOnExecutor方法中的exec.execute(mFuture);是怎么运作的。

public interface Executor {
    void execute(Runnable command);
}

OK,线索又断了,我们继续找exec的构造函数。我们发现调用这个executeOnExecutor时传入的参数是sDefaultExecutor,然后继续找

	private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
	
    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);
            }
        }

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

SerialExecutor 是一个有2个方法的内部类,即execute和scheduleNext是一个类中的,阅读的时候需要注意一下。那么这里一下子就涉及到了两个线程池,我们原来提到,一个是负责任务的排序,一个用于真正执行任务。那么带着这个去看,很容易发现SERIAL_EXECUTOR 是负责任务的排队的,它在execute方法中将runnable放入mTasks队尾,然后判断当前mActive是否为空,如果不为空在调用scheduleNext()方法。然后在scheduleNext中取出任务队列中的队首任务,如果不为null则赋值给mActive对象并传入THREAD_POOL_EXECUTOR进行执行。
而THREAD_POOL_EXECUTOR则是在静态代码块的时候就构造了,也是一个线程池。
那么现在的源码流程已经结束了,还有一个问题就是doInBackground到底是调用在什么线程中的。
我们还是得看一下FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
     
     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);
        }
    }
}

这里只展示了几个重要的方法,可以看到,这里的run方法中有 result = c.call();这个c就是我们的mWorker,这也解释了doInBAckgournd是运行在子线程中。

发布了57 篇原创文章 · 获赞 3 · 访问量 6219

猜你喜欢

转载自blog.csdn.net/qq_39830579/article/details/88751598