Android异步处理类AsyncTask
但凡接触过Android开发的人都知道UI线程是不能进行耗时操作的,否则有可能出现ANR。那么为了避免这个问题Android提供了AsyncTask来处理耗时任务如网络请求,数据库的读取等。那么接下来让我们看看AsyncTask是怎么实现的吧。
首先来看看AsyncTask的使用:
public classMainActivity extends AppCompatActivity {public static finalStringTAG="MainActivity";@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//任务串行执行new MyTask().execute("");//任务并行执行new MyTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECU TOR,"");} private static classMyTask extends AsyncTask { //在执行任务之前调用(UIThread)@Overrideprotected voidonPreExecute() {super.onPreExecute();Log.e(TAG,"onPreExecute:"+Thread.currentThread().getName());}//在执行任务执行时调用(WorkThread)返回值传入onPostExecute@Overrideprotected String doInBackground(String... params) {//耗时操作代码try{for(inti =0;i <5;i++) {Thread.sleep(1000);onProgressUpdate(i*20);}}catch(InterruptedException e) {e.printStackTrace();}Log.e(TAG,"doInBackground:"+Thread.currentThread().getName() );return null;}//在执行任务执行百分比(WorkThread)@Overrideprotected voidonProgressUpdate(Integer... values) {super.onProgressUpdate(values);Log.e(TAG,"onProgressUpdate:"+Thread.currentThread().getName() );}//在执行任务执行完成调用(UIThread)@Overrideprotected voidonPostExecute(String s) {super.onPostExecute(s);Log.e(TAG,"onPostExecute:"+Thread.currentThread().getName());}}}
源码分析
AsyncTask如何工作?
首先来看execute()和executeOnExecutor()方法:
@MainThreadpublic final AsyncTask execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);}
在这方法中会执行executeOnExecutor()这个方法,在这方法中又干了什么?
@MainThreadpublic 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; }
从中可看出先执行的是onPreExecute()--> exec.execute(mFuture);
exec就是execute方法传入的也就是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 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); } }}
这个线程池也就是串行器的实现,我们来分析下它的实现:
首先是
final ArrayDeque
mTasks = new ArrayDeque ();
这是一个线性的双向队列,用于存储AsyncTask任务,当有新的任务时就是调用mTasks.offer()(此方法将指定的元素,在此deque队列的末尾);然后执行scheduleNext();在这方法中会执行队列中排列最前的任务THREAD_POOL_EXECUTOR.execute(mActive);
下面是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);
可以看出线程池核心容量的容量是cpu核心数 +1;线程池最大容量为cpu核心数* 2 + 1;过剩的空闲线程的存活时间为1秒;待执行的任务队列初始容量:128个 。
通过上面的分析可以知道,不管是串行执行任务还是并行执行,其中的区别就是传入给executeOnExecutor()的线程池的不同,串行就是sDefaultExecutor,当然也可以指定自己定义的串行器,而并行则可以自己指定线程池来执行。
分析完任务的串行和并行的执行之后,接下来来看看doInBackground()是何时开始执行以及是如何将执行结果返回给onPostExecute()的:首先在AsyncTask的构造方法中定义了个WorkerRunnable implements Callable和一个FutureTask,不了解Callable和Future的可以看这里,我们看下构造方法中WorkerRunnable的实现
mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //任务开始执行 Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); }};
通过上面代码可以发现执行后将结果交给postResult(result)方法处理,那我们在来看看这个方法的实现:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result;}
看到这个方法后就明白了,AsyncTask的原理就是封装了handler+Thread。
总结:
AsyncTask内部封装了Thread和Handler,调用AsyncTask的executeOnExecutor方法可以实现任务的并行执行也可以自定义线程池,调用execute方法可以实现任务的串行执行。
更多相关文章
- android对大图片压缩的方法
- android访问静态页面,出现405错误解决方法
- cocos2dx 玩转震动
- Android(安卓)开发
- Android事件分发机制的探索与发现之View篇
- android显示意图激活另一个Activity的方法
- ubuntu下android真机调试
- Android显示图片崩溃的解决办法
- Android(安卓)Fragment与Fragment、Activity通信的方式的总结