AsyncTask<Params, Progress, Result>是一个抽象类,常用用于被继承,继承AsyncTask需要指定如下三个泛型参数:
Params:启动任务时输入参数的类型
Progress:启动后台任务中返回进度值的类型
Result:后台执行任务完成后返回结果类型
doInBackground:必须重写,异步执行后台线程将要完成的任务,异步操作主体
onPreExecute:执行后台耗时操作前被调用,通常用户完成一些初始化操作
onPostExecute:当doInBackground完成后,系统自动调用此方法,并将doInBackground方法返回的值传递给该方法
onProgressUpdate:在doInBackground方法中调用publishProgress方法更新任务的执行进度后,会触发该方法
构建一个类继承自AsyncTask(参数后面再谈,最基本的是Void)
public class MyAsyncTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { Log.i("tag", "doInBackground"); return null; } @Override protected void onPreExecute() { Log.i("tag", "onPreExecute"); super.onPreExecute(); } @Override protected void onPostExecute(Void result) { Log.i("tag", "onPostExecute"); super.onPostExecute(result); } @Override protected void onProgressUpdate(Void... values) { Log.i("tag", "onProgressUpdate"); super.onProgressUpdate(values); } }在MainActivity中启动该异步线程
MyAsyncTask task = new MyAsyncTask(); task.execute();
会发现没有onProgressUpdate方法的Log信息,是因为没有在doInBackground中调用publishProgress方法。
@Override protected Void doInBackground(Void... params) { Log.i("tag", "doInBackground"); onProgressUpdate(); return null; }
private static final String[] imageUrl = { "http://hiphotos.baidu.com/vermouthtj/pic/item/7bf1cf1bb6cf6de5ae513373.jpg", "http://b.hiphotos.baidu.com/zhidao/pic/item/dc54564e9258d1092285920fd758ccbf6c814d2c.jpg", "http://img1.3lian.com/img013/v4/89/d/23.jpg" };
ImageLoadAsyncTask task = new ImageLoadAsyncTask(); task.execute(imageUrl[0], imageUrl[1], imageUrl[2]);
/** * Params:String是线程运行的初始参数 * Progress:不需要一个加载进度,因此为Void * Result:当线程结束后返回的数据 * * @author 李波 * */ class ImageLoadAsyncTask extends AsyncTask<String, Void, Bitmap> { @Override protected Bitmap doInBackground(String... params) { Log.i("tag", "" + params.length); Bitmap[] bitmap = new Bitmap[3]; URLConnection connection;// 定义网络连接对象 InputStream is;// 获取数据的输入流 // params是一个可变长数组,因此可以在线程启动时传递多个String,然后通过数组的方式取出URL for (int j = 0; j < params.length; j++) { String url = params[j]; try { // 获取网络连接对象 connection = new URL(url).openConnection(); is = connection.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); bitmap[j] = BitmapFactory.decodeStream(bis); Thread.sleep(2000); is.close(); bis.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bitmap[1]; } @Override protected void onPreExecute() { mProgressBar.setVisibility(View.VISIBLE); super.onPreExecute(); } @Override protected void onPostExecute(Bitmap bitmap) { // 可在此方法中更新UI super.onPostExecute(bitmap); mProgressBar.setVisibility(View.GONE); mImageView.setImageBitmap(bitmap); } }
mProgerssbar = (android.widget.ProgressBar) findViewById(R.id.progressbar1); task = new myAsyncTask(); task.execute();
class myAsyncTask extends AsyncTask<Void, Integer, Void>{ @Override protected Void doInBackground(Void... params) { //模拟进度更新 for (int i = 0; i < 100; i++) { publishProgress(i); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); //获取进度更新值,values同样是一个可变长度数组 mProgerssbar.setProgress(values[0]); } }这样ProgressBar能显示进度,但是重复开启线程时,就会发现从第二个往后都没有效果,这是因为前一个线程还没有执行完毕,需要依次执行,所以会出现ProgressBar不动的情况。
解决办法是将AsyncTask与Activity的生命周期绑定
@Override protected void onPause() { super.onPause(); if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) { task.cancel(true); } }可上述代码只是对线程的提供停止建议,其中cancel方法实际是将AsyncTask标记为cancel状态,并不是立即停止。实际还是需要等待线程执行完毕才能够轮询到下一线程。
因此,可以这么解决,当Activity的onPause方法得到调用时,标记了cancel状态,然后在线程的doInBackground方法中去检测状态值的改变,如果为true,则跳出循环,终止数值的增加,线程的任务结束了进而停止线程。
if (isCancelled()) { break; }在onProgressUpdate方法中做类似处理
if (isCancelled()) { return; }
1.必须在UI线程也就是主线程中创建AsyncTask实例
2.必须在UI线程中调用AsyncTask的execute方法
3.重写四个父类方法,其中只有doinBackground方法是运行在另外一个线程的,其他方法都是在主线程,因此可以更新UI
4.每个AsyncTask只能被执行一次,多次调用会引发异常,即execute方法不能写两遍