在以前的文章深刻探究了Handler,《从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)》咱们知道了Android的消息机制主要靠Handler来实现,可是在Handler的使用中,忽略内存泄露的问题,无论是代码量仍是理解程度上都显得有点不尽人意,因此Google官方帮咱们在Handler的基础上封装出了AsyncTask。可是在使用AsyncTask的时候有不少细节须要注意,它的优势到底体如今哪里?仍是来看看源码一探究竟。java
来一段日常简单使用AsyncTask来异步操做UI线程的状况,首先新建一个类继承AsyncTask,构造函数传入咱们要操做的组件(ProgressBar和TextView)android
class MAsyncTask extends AsyncTask<Void, Integer, String>{ private ProgressBar mProgressBar; private TextView mTextView; public MAsyncTask(ProgressBar mProgressBar, TextView mTextView) { this.mProgressBar = mProgressBar; this.mTextView = mTextView; } @Override protected void onPreExecute() { mTextView.setText("开始执行"); super.onPreExecute(); } @Override protected String doInBackground(Void... params) { for(int i = 0; i <= 100; i++){ publishProgress(i);//此行代码对应下面onProgressUpdate方法 try { Thread.sleep(100);//耗时操做,如网络请求 } catch (InterruptedException e) { e.printStackTrace(); } } return "执行完毕"; } @Override protected void onProgressUpdate(Integer... values) { mProgressBar.setProgress(values[0]); super.onProgressUpdate(values); } @Override protected void onPostExecute(String s) { mTextView.setText(s); super.onPostExecute(s); } }
在Activity中建立咱们新建的MAsyncTask实例而且执行(无关代码省略):segmentfault
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { ... MAsyncTask asyncTask = new MAsyncTask(mTestPB, mTestTV); asyncTask.execute();//开始执行 ... } }
在上面的代码,咱们开了个单一的线程来执行了一个简单的异步更新UI的操做(哈哈,可能会以为AsyncTask有些大材小用了哈),如今来看看AsyncTask具体是怎么实现的,先从构造方法开始:网络
public abstract class AsyncTask<Params, Progress, Result>
AsyncTask为抽象类,而且有三个泛型,我以为这三个泛型是不少使用者不懂的根源:多线程
看了这三个泛型,咱们就基本上了解了AsyncTask的执行过程,主要就是上面代码重写的那几个方法,如今来仔细看,首先在继承AsyncTask时有个抽象方法必须重写:并发
@WorkerThread protected abstract Result doInBackground(Params... params);
顾名思义,这个方法是在后台执行,也就是在子线程中执行,须要子类来实现,在这个方法里面咱们能够调用publishProgress来发送进度给UI线程,而且在onProgressUpdate方法中接收。异步
根据调用顺序,咱们通常会重写这几个方法:async
//在doInBackground以前调用,在UI线程内执行 @MainThread protected void onPreExecute() { } //在执行中,且在调用publishProgress方法时,在UI线程内执行,用于更新进度 @MainThread protected void onProgressUpdate(Progress... values) { } //在doInBackground以后调用,在UI线程内执行 @MainThread protected void onPostExecute(Result result) { }
咱们来看看这个publishProgress方法是怎么来调用onProgressUpdate方法的:ide
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
使用obtainMessage是避免重复建立消息,调用了getHandler()而后发送消息,这里是一个单例函数
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
返回了一个InternalHandler:
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } } }
在判断消息为MESSAGE_POST_PROGRESS后咱们发现其实内部就是调用了Handler来实现这一切,包括执行结束时调用finish方法,这个咱们后面再说。从头来看一下AsyncTask的执行过程,来到execute方法:
/** This method must be invoked on the UI thread.(这行注释为Google官方注释) */ @MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
注意!此方法必须在UI线程调用,这里就不作测试了。在这里又调用executeOnExecutor:
@MainThread public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { ...... onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }
咱们发如今UI线程先调用了onPreExecute(),将传入的参数赋值给mWorker.mParams,而后调用了参数exec的execute方法,而且将mFuture做为参数传入,这里就设计到了三个对象:sDefaultExecutor(在executeOnExecutor中传入)、mWorker、mFuture,来看看它们的赋值在哪里:
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); } } }
咱们发现sDefaultExecutor的赋值默认就是SERIAL_EXECUTOR,也就是一个顺序执行的线程池,内部实现有一个任务队列。
private final WorkerRunnable<Params, Result> mWorker; public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { 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 static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
在AsyncTask的构造方法中,给mWorker赋值为一个Callable(带返回参数的线程,涉及到java并发的一些基础知识,这里不赘述),而且在call方法中执行了doInBackground方法,最后调用postResult方法
private final FutureTask<Result> mFuture; public AsyncTask() { ...... 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); } } }; }
mFuture为FutureTask类型,这里将mWorker传入,在mWorker执行完毕后调用postResultIfNotInvoked方法,咱们先看看这个方法:
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } }
其实这个方法也最后调用了postResult,在这以前作了个有没调用的判断,确保任务执行完毕后调用此方法。来看看postResult方法:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
又看到了熟悉的obtainMessage和sendToTarget发送消息,此次消息内容变为MESSAGE_POST_RESULT,再来看看咱们刚才已经提到的InternalHandler的handleMessage方法:
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; } }
最后根据消息类型,这里调用了result.mTask.finish,result类型为AsyncTaskResult:
private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
mTask的类型为AsyncTask,找到AsyncTask的finish方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
最后若是没有取消的话调用了onPostExecute,也就是咱们以前重写的那个方法,在执行完毕后调用,而且此方法也在子线程。
正如开题所说,AsyncTask本质上就是对Handler的封装,在执行以前,执行中,执行完毕都有相应的方法,使用起来也一目了然,不过这还并非AsyncTask的最大的优势,AsyncTask最适合使用的场景是多线程,开始在代码中已经看到了在AsyncTask内部有本身维护的线程池,默认的是SERIAL_EXECUTOR
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
按照顺序执行,一个任务执行完毕再执行下一个,还提供有一个支持并发的线程池:
//获取CPU数目 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //核心工做线程(同时执行的线程数) private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //线程池容许的最大线程数目 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //空闲线程超时时间(单位为S) private static final int KEEP_ALIVE = 1; //线程工厂 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()); } }; //阻塞队列,用来保存待执行的任务(最高128个) private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
声明为static,多个实例同用一个线程池,这个是Googl官方自带的一个根据cpu数目来优化的线程池,使用方法以下:
for(int i = 0; i < 100; i++) {//模拟100个任务,不超过128 MAsyncTask asyncTask = new MAsyncTask(mTestPB, mTestTV); asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
在executeOnExecutor中咱们还能够传入本身自定义的线程池:
//跟默认同样的按顺序执行 asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor()); //无限制的Executor asyncTask.executeOnExecutor(Executors.newCachedThreadPool()); //同时执行数目为10的Executor asyncTask.executeOnExecutor(Executors.newFixedThreadPool(10));
AsyncTask使用起来的确很简单方便,内部也是Android的消息机制,而且很快捷的实现了异步更新UI,特别是多线程时也能够很好的表现,这个是咱们单独使用Handler时不具有的,可是在使用过程当中注意内部方法的调用顺序以及调用的时机,好比asyncTask.execute() 要在UI主线程中调用,在子线程中调用是不能够的,还有就是在使用时根据状况来决定到底应该用哪一种线程池。