housezhu 2015-03-16
android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI线程。
AsyncTask定义了三种通用类型:Params, Progress和Result,Params表示异步任务执行时传入的参数,Progress表示异步任务执行过程中发布的数据,Result表示异步任务执行的结果。
AsyncTask还定义了四个回调函数:onPreExecute, doInBackground, onProgressUpdate和onPostExecute来管理异步操作的过程:
1. onPreExecute(), 异步任务开始执行时,由UI线程调用,比如在UI上展示进度条。
2. doInBackground(Params...), onPreExecute()执行完后,立即由后台线程调用. 该方法用来执行后台的操作,可能需要花费不少时间。参数Params传入该方法,处理结果返回并作为最后一步onPostExecute(Result) 的参数值传入。该方法内,还可以使用方法publishProgress(Progress...)来发布异步操作的进展状态,发布的进展状态数据作为 onProgressUpdate(Progress...)的参数传入,被UI线程调用。
3. onProgressUpdate(Progress...), 和2提到的一样,该方法在publishProgress(Progress...)执行后,由UI线程调用。该方法用来在UI上展示后台操作正在执行的 任何状态,不能确定它会执行多久。比如,它可以使用动画来呈现执行过程的状态栏或者在Text里展示执行日志等。
4. onPostExecute(Result), 后台线程操作完毕后,由UI线程调用,doInBackground(Params...)的返回值作为其参数传入。
要实现这样的异步任务,我们必须使用一个类继承自AsyncTask,并且该子类至少要重载doInBackground(Params...)方法,我 们还经常需要重载onPostExecute(Result)方法。下面是一个继承自AsyncTask的子类的例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } }
通过以下代码即可启动该异步任务:
new DownloadFilesTask().execute(url1, url2, url3);
可以通过调用方法cancel(boolean)来取消异步任务,该方法会使UI线程在方法doInBackground(Object[]) 返回后调用方法onCancelled(Object),并且方法onPostExecute(Object)将不会被调用。 cancel(boolean)调用后,应该在方法doInBackground(Object[])里周期性的检查isCancelled()的返回 值,以尽早知道异步任务是否已经取消了。
AsyncTask实例必须在UI线程里创建,并且方法execute(Params...)必须在UI线程里执行。不要手动调用 onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) 这几个回调函数。AsyncTask实例只能被执行一次,试图去执行第二次将会跑出异常。