AsyncTask源码浅析
来源:互联网 发布:thinkphp手机商城源码 编辑:程序博客网 时间:2024/06/05 06:45
在开发的过程中我们如果想进行一些耗时的操作不能直接在UI线程中进行,除了使用Handler机制来进行异步消息处理,Android还给我们提供了一个非常方便的类AsyncTask来进行异步操作,在这篇文章中只对AsyncTask的源码进行一下梳理,如果对AsyncTask的使用还不太熟悉的可以先看一下API的使用方法。
我们往往是定义一个类继承AsyncTask,然后创建出这个类的实例,而后调用execute方法来执行任务,我们就从这里入手来分析源码,首先是构造方法:
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; 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 occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
首先看一下代码的注释,告诉我们这个构造器必须在UI线程中进行调用,这个在后面会给出分析。构造方法很简单,分别对创建出了WorkerRunnable和FutureTask对象并将其保存起来。先看看WorkerRunnable是什么东西:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
实现了Callable接口(可以简单的将Callable对象看做一个执行run方法时有返回值的Runnable对象,只不过在Callable中改名叫call方法),是一个抽象类,在构造函数中重写了call方法,暂时先不用考虑里面的逻辑,后面会进行分析。
再看FutureTask类,它的构造方法中接受了一个Callable参数,也就是我们刚刚创建出来的WorkerRunnable对象,看一下它的方法列表不难找到一个比较熟悉的方法,run方法,我们进入看一下:
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, 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); } }
只看一下关键的部分,在这个方法中调用了Callable对象的call方法。
构造函数已经简单的分析完了,现在来看一下我们经常调用的execute方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
可以看到,它只是简单的调用了另一个方法,但是出现了一个没有见过的参数sDefaultExecutor,来看一下这个参数是什么:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/** * An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process. */ 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); } } }
代码不是很多,首先在线程池中维护了一个双端队列的实例,并且在线程池的execute方法中并没有执行传入的Runnable对象,而是将它用另一个新创建的Runnable对象包装起来放到队列的尾部。显然,在第一次调用execute方法的时候mActive对象一定是null,这个时候会调用scheduleNext方法将队列中的元素拿出来,并且使用THREAD_POOL_EXECUTOR来执行它,看一下THREAD_POOL_EXECUTOR的代码:
/** * An {@link Executor} that can be used to execute tasks in parallel. */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
只是创建了一个固定规格和模式的线程池,这里不是分析的重点就不去深入它了。在执行完成后可以看到无论如何都会执行到SerialExecutor中execute方法的finally语句中,在这里又调用了scheduleNext进行重复的工作。通过上面的分析也就不难理解注释中说明的一次只能执行一个任务,虽然没有继续分析,但是可以猜想出AsyncTask的任务是由SerialExecutor进行分配,并且由于它是static的,在同一个进程内所有的AsyncTask中的任务都会放入到这个类的队列中按顺序执行。
接着回到AsyncTask的execute方法中,调用了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(); mWorker.mParams = params; exec.execute(mFuture); return this; }
在这里可以看到熟悉的onPreExecute方法被调用了,由于前面的注释中说过,AsyncTask类对象的创建必须是在主线程中执行的,所以onPreExecute方法的执行也是在主线程中的。而后将传入的参数赋给了mWorker对象中的数组,使用传入的线程池对mFuture进行执行,因为传入的参数是sDefaultExecutor,所以执行的逻辑跳转回了SerialExecutor的execute方法,而后在线程池中执行了mFuture的run方法。根据我们前面的分析它的run方法调用了mWorker的call方法,那么call方法是在哪里实现的呢,没错,在构造函数中:
public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); }
在这里执行了doInBackground方法,这个方法应该很熟悉了,它是一个抽象的方法,也是每次都要求我们必须进行重写的。这里由于执行过程还是在线程池中进行的,所以避免了在UI线程中进行耗时操作。方法执行完成后将返回值作为参数传递给了postResult方法,进入看一下:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
在这里面看到了很熟悉的代码,Handler机制,那么这个Handler是在哪创建的呢,
private static final InternalHandler sHandler = new InternalHandler();
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; } } }
很显然Handler类是静态的,在类加载的时候就会初始化这个类,现在回过头再来想一下刚才提到的AsyncTask一定要在UI线程中加载的问题,如果不在UI线程中进行加载,那么Handler自然也就不在UI线程中,那么onProgressUpdate方法和onPostExecute方法中也就不能执行更新UI的操作了。
继续看postResult方法,很简单,就是给Handler发了一个消息并且传了一个参数,而Handler调用了AsyncTask的finish方法用到了这个参数,下面是finish方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
在任务被取消时调用onCancelled方法回调,不然就调用我们熟悉的onPostExecute方法。而在Handler的handleMessage中还有一个接收项,它回调了我们常用的onProgressUpdate方法,找一下这个标记(MESSAGE_POST_PROGRESS)是怎样传入的,不难找到publishProgress方法:
protected final void publishProgress(Progress... values) { if (!isCancelled()) { sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
这也正是我们在doInBackground中经常使用的。
0 0
- AsyncTask源码浅析
- AsyncTask源码浅析
- 读AsyncTask源码之浅析
- AsyncTask浅析
- AsyncTask浅析
- AsyncTask浅析
- AsyncTask源码
- AsyncTask源码
- AsyncTask源码
- AsyncTask源码
- Android AsyncTask 原理浅析
- AsyncTask源代码浅析(一)
- AsyncTask类浅析
- 浅析android中AsyncTask
- android AsyncTask问题浅析
- 浅析AsyncTask运行异步任务
- AsyncTask源码解析
- AsyncTask 源码研究
- SSH整合时tomcat启动报错问题
- 算法练习四:重建二叉树
- 数据结构例程——平衡二叉树
- JDBC驱动类型
- ios编程360相机滤镜
- AsyncTask源码浅析
- Http协议网络请求java方式
- [转]Android关于使用混淆文件proguard-project.txt笔记
- cell selectedBackgroundView区域大于cell的异常
- POJ 2533 O(nlogn)解最长递增子序列(构造法)
- Java中CountDownLatch、CyclicBarrier、Thread.join方法基本应用
- Oracle 执行计划 Explain plan for
- mysql存储过程中三种循环
- APP的安装卸载测试