answer1991无法停止我内心的狂热,对未来的执着。 Android AsyncTask运作原理和源码分析
上述是AsyncTask的全部代码。
AsyncTask多用于Android的Context(Activity)处理后台逻辑同时又要兼顾主线程的一些逻辑(比如说Activity的UI更新)。
AsyncTask它其实是封装了一个多线程、向开发者屏蔽了考虑多线程的问题。开发人员只需去重写AsyncTask中的 doInBackground、onProgressUpdate、onPreExecute、onPostExecute等方法,然后生成该对象并执行 execute方法即可实现异步操作。
由于Android负责Context(Activity)的主线程(或者说是UI控制线程)不是线程安全的,也就是说开发者不能在自己生成的线程对象里面操作Activity的UI更新。
对于习惯了Java开发的开发人员来说,非要自己生成线程对象,在这个线程里操作一些时间较长的逻辑(比如下载文件),完成之后再提醒用户下载完成(UI 更新,比如在一个TextView中把文字修改成"下载完成")的话,那么UI更新的工作只能借助于Handler(这个Handler必须是在主线程中 生成,或者说和主线程共用一个Looper和MessageQueue,通常的方法是在Activity中的onCreate方法中生成重写的 Handler对象)。当开发者的线程完成逻辑操作之后,发送一个消息到Handler,再由Handler去处理。如果Handler由主线程生成,那 么这个Handler的handleMessage()会在主线程中执行,因此在handleMessage()中可以访问Activity中的某个 View并修改。如一下代码:
上述的方法也未尝不是一种好的方法。然而Android为开发者提供了一种新的解决方案,那就是AsyncTask,分析完源代码会发现,其实AsyncTask为我们封装了上述的方法。
对于我们重写AsyncTask的doInBackground()的方法,AsyncTask会将它封装成一个实现Callable接口的对象,在线程池中找出一个线程是实现它,因此我们所需要的耗时较长的逻辑可以放在这个方法里面。
AsyncTask也维护着一个静态的Handler,这个Handler属于创建AsyncTask的线程,而创建AsyncTask一般都是主线程(UI线程),因此这个Handler可以访问并Activity的UI。
可以看到这个Handler操作了AsyncTask的三个方法:finish() , onProgressUpdate() , onCancelled(),而finish() 又调用onPostExecute()方法。
可以这么说,onProgressUpdate() ,onCancelled(),onPostExecute() 用来被开发者重写,去更新UI的,这3个方法会涉及到UI的操作,因此doInBackground()方法里不能调用这几个方法,也就是说开发者可以重 写这些方法,但是又不能直接调用这些方法,只能通过发送消息给Handler的方式来隐式的调用。
onProgressUpdate()是一个更新处理进度的方法,开发者可以重写它,可以将它关联到Activity的一个进度条控件上,在 doInBackground()里可以用publishProgress()去间接调用它(其实这个函数也是通过发送what为 MESSAGE_POST_PROGRESS的Message给Handler的方式来调用onProgressUpdate()的),这样就能在UI上 显示进度信息。
finish()方法,也就是onPostExecute(),是处理完doInBackground()得到结果之后的调用。 doInBackground()的函数封装在实现Callable接口的名叫一个WorkerRunnable的抽象类中,再将这个类封装在 Future中,并重写Future的done()方法,这个方法会在Callable的call方法执行完之后调用,就是 doInBackground()方法执行完之后调用,它可以获得执行完的结果,Future.get()方法(可能阻塞),并将得到的结果封装在 what为MESSAGE_POST_RESULT的Message中,并发送。上诉的核心代码如下:
同理,onCancelled()是在AsyncTask被取消时的调用,也是通过Handler的方法。
有一点要注意到,还有一个onPreExecute()方法,虽然这个方法是未被Handler加入到消息处理的方法里,但是这个方法是在execute()里执行的,execute是主线程(UI线程)才会去执行的,所以这个方法也能访问和修改UI。
总结: 开发者可以重写AsyncTask的onProgressUpdate() , onCancelled(), onPostExecute(), onPreExecute(), doInBackground()方法,以得到异步实现后台逻辑并更新UI的操作。
其中onProgressUpdate() , onCancelled(), onPostExecute(), onPreExecute() 可以直接访问并修改UI。
但是doInBackground()不能出现涉及UI的操作,也不能直接调用onProgressUpdate() , onCancelled(), onPostExecute(), onPreExecute() 这四个方法,后三者不需要调用,可以通过publishProgress()去间接的调用onProgressUpdate()方法。
最后要说的是AsyncTask的对象一旦生成之后,execute()方法只能被调用一次,即使是同样的操作,也需要重新生成AsyncTask对象才行。
PS:本文是原创,作者正在找工作中,适合Android和J2EE的开发。有意者请发送邮件到 answer1991.chen@gmail.com 。 |
|
来自: android之情殇 > 《android》