AsyncTask源码深入解析

最近想写一篇关于源码解析的文章,发现AsyncTask代码量不多,可里面的东西却是很值得学习的,所以故那这来“开刀”

首先作为Android开发者我们对于AsyncTask想必比大家都知道吗,大白话讲就是在后台执行耗时任务再把最终的结果返回主线程更新UI。如下代码就它的模板代码:

class MyAsyncTack extends AsyncTask{
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //doInBackground执行前一些初始化的操作都在这里
    }

    @Override
    protected String doInBackground(Void... voids) {
        //后台耗时任务执行中。。。
        return null;
    }
    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        //后台执行的任务会发回一个或多个阶段性进度结果,这个是可以用来去更新交互页面。
    }
    @Override
    protected void onCancelled() {
        super.onCancelled();
        //在后台任务被取消时回调
    }
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        //耗时任务完成返回结果,刷新ui
    }
}
    
//执行AsycnTask
MyAsyncTack myAsyncTack=new MyAsyncTack();
myAsyncTack.execute();
    

这就是整的一个AsyncTask模板代码了。

从上面的模板中,整个过程是从myAsyncTack.execute();开始的,那我们就execute()开始吧
AsyncTask关于这部分的源码如下:

@MainThread
public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
}

@MainThread
public final AsyncTask 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通过判断Status来防止AsyncTask多次执行,然后调用了onPreExecute();抽象方法,为任务的执行做一些准备和初始化操作。接着有三个对于现在我们来说很陌生的变量(mWorker,exec,mFuture).

对于mWorker,mFuture这两个变量在AsyncTask这个类初始化的时候就已经初始化了,对应的关键源码如下

public AsyncTask() {
    this((Looper) null);
}

private static abstract class WorkerRunnable implements Callable {
    Params[] mParams;
}

public AsyncTask(Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper);
        mWorker = new WorkerRunnable() {
            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;
            }
        };

        mFuture = new FutureTask(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);
                }
            }
        };
}

如上所示,mWorker很简单,就是AsycnTask里面的抽象内部类,实现了Callable接口,接下来就是mFuture即FutureTask,对于平时写业务层的我们对这个FutureTask类接触的还是比较少而又是这篇文章的重点,所以重点讲。

FutureTask

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。概念总是难以理解,所以给你们一个关于使用FutureTask的demo,这个demo就是整个AsyncTask的核心。

public class FutureTest1 {

    public static void main(String[] args) {
        Task task = new Task();// 新建异步任务
        FutureTask future = new FutureTask(task) {
            // 异步任务执行完成,回调
            @Override
            protected void done() {
                try {
                    System.out.println("future.done():" + get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        };
        // 创建线程池(使用了预定义的配置)
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(future);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        // 可以取消异步任务
//         future.cancel(true);
        try {
        // 阻塞,等待异步任务执行完毕-获取异步任务的返回值
            System.out.println("future.get():"+future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    // 异步任务
    static class Task implements Callable {
        // 返回异步任务的执行结果
        @Override
        public Integer call() throws Exception {
            int i = 0;
            for (;i<10;i++) {
                try {
                   System.out.println(Thread.currentThread().getName()+"_"+ i);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return i;
        }
    }

}

上面demo运行结果如下:

AsyncTask源码深入解析_第1张图片
FutureTask.PNG

FutureTask可以获取异步任务线程的最终结果,所以future.get()返回10。

回到我们的AsyncTask里,同理如上面demo一样,会先执行mWorker的call()里面的方法,call方法里就执行抽象方法doInBackground(mParams);我们就这回到方法里执行耗时任务,然后拿到结果执行postResult(result)方法,而Future的get()也可以从Callable拿到执行的结果。

  • 分析exec.execute(mFuture);
    首先exec我们要知道exec是什么?顺着他的源码向上找,代码如下:
@MainThread
public final AsyncTask execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

这个sDefaultExecutor是什么呢,再顺着这推,关键源码如下:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

private static class SerialExecutor implements Executor {
    final ArrayDeque mTasks = new ArrayDeque();
    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);
        }
    }
}

ArrayDeque是一个先进先出的队列存储Runnable对象,offer方法加到队尾,poll()从队头取,当运行的第一次的时候mActive就是空的,所以还是从mTask取出一个由THREAD_POOL_EXECUTOR执行,等下一次是mActive不为空就通过finally去执行 scheduleNext();方法,这段代码里有两个讲解点,分别是 r.run();和THREAD_POOL_EXECUTOR

  • 首先r.run()调用的是哪个方法呢
    通过exec.execute(mFuture);我们知道上面的Runnable就是mFuture,即调用了mFuture.run();而这个源码如下:
private Callable callable;

public FutureTask(Callable 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 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 = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

我已经把相关的代码都截出来的很详尽了,可以看出callable就是我们上面的mWorker变量,然后就是调mWorker.call()方法执行抽象方法doInBackground(),

mWorker = new WorkerRunnable() {
    public Result call() throws Exception {
        mTaskInvoked.set(true);

        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //noinspection unchecked
        Result result = doInBackground(mParams);
        Binder.flushPendingCommands();
        return postResult(result);
    }
};

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

同时我上面FutureTask的demo也和这个形成了对应连贯,这就是我demo的底层实现,最后通过postResult();里的sHandler发送一个MESSAGE_POST_RESULT的消息
我们追踪先关代码:

private static class InternalHandler extends Handler {

public InternalHandler(Looper looper) {
    super(looper);
}

@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
    AsyncTaskResult result = (AsyncTaskResult) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }}
}

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
}

这里反而没什么好讲的,通过handler调用finish()方法,假如没有取消就是调用抽象方法onPostExecute(),假如取消了就调用抽象方法onCancelled();而当handler发送MESSAGE_POST_PROGRESS,就是调抽象方法onProgressUpdate(),很简单没什么说的。

  • 接着分析THREAD_POOL_EXECUTOR,相关源码如下:
 private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue(128);
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
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());
    }
};

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

其实这就是定义了一个线程池。同时运行线程数Math.max(2, Math.min(CPU_COUNT - 1, 4)),线程池总大小CPU_COUNT * 2 + 1;但是由于SerialExecutor的存在,它会强制串行并发,所以实际上只有一个线程在跑,所以也就不存在任务数超过线程池总大小的问题了。当然这是一个默认实现,我特也可以通过public static void setDefaultExecutor(Executor exec)进行更改。

到此整个分析过程就结束了,总结一下AcyncTask汇集了线程池,handler等相关知识,也告诉我们,不管表明多花俏,底层原理才是最重要的,懂得底层原理才能不变应万变,废话有点多了

你可能感兴趣的:(AsyncTask源码深入解析)