之前说了AsyncTask线程池的问题,接下来继续说一下AsyncTask应用上的有关问题。之前用豆瓣的API做应用的时候就发现一个问题,就是使用AsyncTask从豆瓣网站异步下载图片显示在ListView上面,会出现图片错位的现象。下面看一下那段代码:
- package com.android.douban.adapter;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.List;
- import com.android.douban.R;
- import com.android.douban.domain.Book;
- import com.android.douban.util.LoadImageAsynTask;
- import com.android.douban.util.LoadImageAsynTask.LoadImageAsynTaskCallback;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.CompressFormat;
- import android.graphics.BitmapFactory;
- import android.net.Uri;
- import android.os.AsyncTask;
- import android.os.Environment;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.TextView;
- public class BookInfoListAdapter extends BaseAdapter {
- private Context mContext;
- private List<Book> list;
- private LayoutInflater inflater;
- private TextView titleTextView, authorTextView, summeryTextView;
- private ImageView bookImageView;
- public Context getmContext() {
- return mContext;
- }
- public void setmContext(Context mContext) {
- this.mContext = mContext;
- }
- public BookInfoListAdapter(Context mContext, List<Book> list) {
- super();
- this.setmContext(mContext);
- this.list = list;
- }
- @Override
- public int getCount() {
- return list.size();
- }
- @Override
- public Object getItem(int arg0) {
- return arg0;
- }
- @Override
- public long getItemId(int arg0) {
- return arg0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder = null;
- View vi = convertView;
- if (convertView == null) {
- inflater = LayoutInflater.from(mContext);
- vi = inflater.inflate(R.layout.activity_myread_listview_item, null);
- holder.titleTextView = (TextView) vi
- .findViewById(R.id.iv_book_title);
- holder.authorTextView = (TextView) vi
- .findViewById(R.id.iv_book_author);
- holder.summeryTextView = (TextView) vi
- .findViewById(R.id.iv_book_summary);
- holder.bookImageView = (ImageView) vi.findViewById(R.id.img1);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- holder.titleTextView.setText(list.get(position).getTitle());
- holder.authorTextView.setText(list.get(position).getAuthor());
- holder.summeryTextView.setText(list.get(position).getSummary());
- String imageUrl = list.get(position).getBookImageUrl();
- final String imageName = imageUrl.substring(
- imageUrl.lastIndexOf("/") + 1, imageUrl.length());
- File file = new File(Environment.getExternalStorageDirectory()
- .getAbsolutePath() + "/" + imageName);
- if (file.exists()) {
- holder.bookImageView.setImageURI(Uri.fromFile(file));
- System.out.println("使用SD卡缓存图片");
- } else {
- class AsyncTaskLoadImage extends AsyncTask<String, Integer, Bitmap> {
- private ViewHolder holder;
- public AsyncTaskLoadImage() {
- holder=new ViewHolder();
- }
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
- @Override
- protected Bitmap doInBackground(String... params) {
- Bitmap bitmap = null;
- try {
- URL url = new URL(params[0]);
- HttpURLConnection urlConnection = (HttpURLConnection) url
- .openConnection();
- urlConnection.connect();
- int MAX = urlConnection.getContentLength();
- InputStream inputStream = urlConnection
- .getInputStream();
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- byte[] b = new byte[1024];
- int len = 0;
- while ((len = inputStream.read(b)) != -1) {
- byteArrayOutputStream.write(b, 0, len);
- }
- bitmap = BitmapFactory.decodeByteArray(
- byteArrayOutputStream.toByteArray(), 0, MAX);
- inputStream.close();
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return bitmap;
- }
- @Override
- protected void onPostExecute(Bitmap result) {
- super.onPostExecute(result);
- holder.bookImageView.setImageBitmap(result);
- }
- }
- AsyncTaskLoadImage asyncTaskLoadImage = new AsyncTaskLoadImage();
- asyncTaskLoadImage.execute(imageUrl);
- }
- return vi;
- }
- public class ViewHolder {
- TextView titleTextView, authorTextView, summeryTextView;
- ImageView bookImageView;
- }
- }
在这个自定义Adapter中,使用AsyncTask下载图片,然用一级缓存(保存图片到SD卡)。如果ListView显示的图片之前下载过,那么就从SD卡里面加载显示,不去下载,节省流量。表面上看没什么问题,但是实际使用中就会发现图片错位的现象。那图片为什么会错位呢?问题就在于
- if (convertView == null) {
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
那如何解决呢?android为我们提供了setTag()方法。具体做法是:在getView的时候给ViewHolder中的ImageView设置tag,其值为要放置在该ImageView上的图片的url地址。这个tag很重要,在异步下载图片完成回调的方法中,我们使用findViewWithTag(String url)来找到ListView中对应的ImagView,然后给该ImageView设置图片即可。在上面的代码中,就需要加入
- holder.bookImageView.setTag(list.get(position));