对于从网络加载资源,我们需要开启Work Thread来进行加载,但是如果自己去维护一个线程池并且与UI线程进行交互是很繁琐的一件事,android为我们封装了一个类AsyncTask就是为了解决轻量异步加载需求。
我们使用AsyncTask主要是继承AsyncTask抽象类,AsyncTask类有三个参数 AsyncTask<Params, Progress, Result>,分别是输入的参数,用于更新进度的参数,返回的参数,我们在创建 AsyncTask时需要制定这三个泛型参数。
下面介绍一下 AsyncTask的主要方法:
onPreExecute():这个是在异步任务执行之前执行,主要是进行一下控件的初始化
doInBackground(Params... params):这个是AsyncTask的主要执行方法,在onPreExecute():之后执行,用于处理耗时的操作。
onProgressUpdate(Progess... values):这个方法是用来更新进度,需要在doInBackground方法中调用publishProgress(Progress)来通知更新
onPostExecute(Result... result):这个是异步任务执行完调用,进行控件赋值等等
值得一提的是,这四个主要的方法,只有doInBackground是工作在Work Thread,其他的三个方法都是工作在UI线程。
下面来具体使用一下AsyncTask来下载一张网络图片,并且显示进度
布局文件就不写了,就是一个imageview和progressbar。首先创建一个类,MyAsyncTask继承AsyncTask,贴一下具体的代码
class MyAsyncTask extends AsyncTask<String,Integer,Bitmap>{
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
InputStream inputStream = null;
try {
HttpClient httpClient = new DefaultHttpClient();
//通过get请求
HttpGet httpGet = new HttpGet(params[0]);
HttpResponse httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode() ==200){
inputStream = httpResponse.getEntity().getContent();
//获取总长度
long file_length = httpResponse.getEntity().getContentLength();
int len = 0;
byte[] data = new byte[1024];
int total_length = 0;
int value = 0;
while ((len = inputStream.read(data)) !=-1){
total_length+=len;
value = (int)(total_length/file_length*100);
//更新进度
publishProgress(value);
outputStream.write(data,0,len);
}
//Thread.sleep(500);为了效果明显点
byte[] result = outputStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(result,0,result.length);
inputStream.close();
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mProgressBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
imageView.setImageBitmap(bitmap);
mProgressBar.setVisibility(View.GONE);
}
}
这时效果已经出来了,但是使用AsyncTask还有一个问题需要注意,就是当执行耗时操作,没有执行完时退出当前activity,再进入时,并不会马上从新执行,这个是因为AsyncTask是维护一个线程池,只有当之前的线程结束,后面的线程才能被执行,所有我们需要把AsyncTask与activity的生命周期进行绑定,当activity退出时取消AsyncTask。
@Override
protected void onPause() {
super.onPause();
if (myAsyncTask != null && myAsyncTask.getStatus() == AsyncTask.Status.RUNNING) {
myAsyncTask.cancel(true);
}
}
但是这样还是不能真正的取消掉当前的线程,这只是告知当前线程为cancle,我们还需要在doInBackground中进行判断
if(myAsyncTask.isCancelled()){
break;
}
在onProgressUpdate也需要判断
if(myAsyncTask.isCancelled()){
return;
}
这样就可以真正的取消掉当前的线程了