异步任务——AsyncTask

异步任务——AsyncTask

一、基本知识

  • 构建AsyncTask子类的参数

AsyncTask<Params, Progress, Result>是一个抽象类,常用用于被继承,继承AsyncTask需要指定如下三个泛型参数:

Params:启动任务时输入参数的类型

Progress:启动后台任务中返回进度值的类型

Result:后台执行任务完成后返回结果类型

  • 构建AsyncTask子类的回调方法

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();
异步任务——AsyncTask_第1张图片

会发现没有onProgressUpdate方法的Log信息,是因为没有在doInBackground中调用publishProgress方法。

	@Override
	protected Void doInBackground(Void... params) {
		Log.i("tag", "doInBackground");
		onProgressUpdate();
		return null;
	}
异步任务——AsyncTask_第2张图片

二、AsyncTask异步加载网络图片

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);
        }
    }

三、AsyncTask更新ProgressBar

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;
			}

四、AsyncTask注意事项

1.必须在UI线程也就是主线程中创建AsyncTask实例
2.必须在UI线程中调用AsyncTask的execute方法

3.重写四个父类方法,其中只有doinBackground方法是运行在另外一个线程的,其他方法都是在主线程,因此可以更新UI

4.每个AsyncTask只能被执行一次,多次调用会引发异常,即execute方法不能写两遍

五、实用AsyncTask


你可能感兴趣的:(异步任务——AsyncTask)