android 因为要遵守单线程模型必须在UI线程中更新UI,但是一些耗时的操作又不能放在UI线程中,以免引起UI线程阻塞从而导致的响应慢或者UI显示慢等问题,就需要
把这些耗时的操作放在单独的线程中去操作,这样就必然会经常遇见多线程开发的问题。android 提供了两种常用的线程间操作的方式:
一,handler & Thread &message
二,asynctask
今天我们重点来看一下asynctask这个android提供给我们的轻量级的异步类
asynctask正如类名一样这是一个异步任务类,参考android的文档说明,AsyncTask使能够适当和容易使用UI线程。这个类允许我们在UI主线程执行后台的操作
以及发布更新进度而不必通过handler和Thread类。
asynctask被设计成一个助手类让我们不必去通过handler&thread的框架完成后台操作,其实asynctask是对handler&thread的包装来实现的。asynctast设计的本意就是用来
执行短时间的操作,一般最多几秒钟时间。如果你要保持一个长时间的线程运行操作那么强烈建议你通过android提供的各种不同的接口实现,比如java.util.concurrent/Executor/
ThreadPoolExecutor/FutureTask.
asynctask类 AsyncTask<Params, Progress, Result>具有三个通用类型的参数:
- Params 启动任务执行的输入参数,比如HTTP请求的URL。
- Progress 后台任务执行的百分比。
- Result 后台执行任务最终返回的结果,比如String。
用法:
asynctask本身是一个abstract的,我们必须通过继承这个类的子类来实现。子类至少要重写一个函数doInBackground,但是我们通常还要重写另外一个接口onPostExecute
下面是一个实现子类的例子:
* 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));
* // Escape early if cancel() is called
* if (isCancelled()) break;
* }
* return totalSize;
* }
*
* protected void onProgressUpdate(Integer... progress) {
* setProgressPercent(progress[0]);
* }
*
* protected void onPostExecute(Long result) {
* showDialog("Downloaded " + result + " bytes");
* }
* }
在UI线程中实例化子类后,调用new DownloadFilesTask().execute(url1, url2, url3);就可以执行后台操作。
执行步骤:
一旦后台任务执行一般都经过下面四个步骤,
1,onPreExecute
这个函数在任务执行前在UI主线程中被调用,一般是执行对任务的设置工作,比如显示一个进度条给用户。
2,doInBackground
这个函数在onpreExecute执行完成后立即被后台线程执行去处理一些耗时的操作。异步任务传递的参数也被传递到这里,当后台任务处理完成后也将在这里返回处理的结果。
另外,虽然这个函数的执行是在子线程中的,但是我们一般在这个函数中通过publishProgress来不断的更新处理的进度。
3,onProgressUpdate
这个函数会在执行publishProgress后会自动调用onProgressUpdate更新UI线程中的值也就是更新进度条的进度。
4,onPostExecute
这个函数在后台任务完成后被调用,而且doInBackground的返回值会作为这个参数传入到这个函数。
删除后台任务:
一个后台任务可以随时通过cancel()函数来删除。这个删除的动作完成后会在后面调用isCancelled时返回true。执行这个函数后,onCancelled会在doInBackground返回后
被调用而不再调用onPostExecute。为了能够及时删除任务,我们应该在doInBackground中不停的检测isCancelled,如果可以的话比如说在一个循环中不停的检测isCancelled。
asynctask使用必须遵循以下规则:
1,自从你android 4.1开始asynctast 类必须在UI线程中加载。
2,必须在Ui主线程中实例化asynctask
3,execute方法必须在UI线程中调用
4,不能手动调用onPreExecute doInBackground onProgressUpdate onPostExecute这几个方法
5,asynctask实例化后只能被执行一次,否则将会抛出异常