Android_AsyncTask详解及其应用(三)_图片错位以及AsyncTask重复创建的问题

来源:互联网 发布:mac换电池 编辑:程序博客网 时间:2024/05/16 05:25

http://blog.csdn.net/wangjinyu501/article/details/9008203


之前说了AsyncTask线程池的问题,接下来继续说一下AsyncTask应用上的有关问题。之前用豆瓣的API做应用的时候就发现一个问题,就是使用AsyncTask从豆瓣网站异步下载图片显示在ListView上面,会出现图片错位的现象。下面看一下那段代码:

            

[java] view plaincopy
  1. package com.android.douban.adapter;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.io.InputStream;  
  9. import java.net.HttpURLConnection;  
  10. import java.net.MalformedURLException;  
  11. import java.net.URL;  
  12. import java.util.List;  
  13. import com.android.douban.R;  
  14. import com.android.douban.domain.Book;  
  15. import com.android.douban.util.LoadImageAsynTask;  
  16. import com.android.douban.util.LoadImageAsynTask.LoadImageAsynTaskCallback;  
  17. import android.content.Context;  
  18. import android.graphics.Bitmap;  
  19. import android.graphics.Bitmap.CompressFormat;  
  20. import android.graphics.BitmapFactory;  
  21. import android.net.Uri;  
  22. import android.os.AsyncTask;  
  23. import android.os.Environment;  
  24. import android.view.LayoutInflater;  
  25. import android.view.View;  
  26. import android.view.ViewGroup;  
  27. import android.widget.BaseAdapter;  
  28. import android.widget.ImageView;  
  29. import android.widget.TextView;  
  30.   
  31. public class BookInfoListAdapter extends BaseAdapter {  
  32.   
  33.     private Context mContext;  
  34.     private List<Book> list;  
  35.     private LayoutInflater inflater;  
  36.     private TextView titleTextView, authorTextView, summeryTextView;  
  37.     private ImageView bookImageView;  
  38.   
  39.     public Context getmContext() {  
  40.         return mContext;  
  41.     }  
  42.   
  43.     public void setmContext(Context mContext) {  
  44.         this.mContext = mContext;  
  45.     }  
  46.   
  47.     public BookInfoListAdapter(Context mContext, List<Book> list) {  
  48.         super();  
  49.         this.setmContext(mContext);  
  50.         this.list = list;  
  51.     }  
  52.   
  53.     @Override  
  54.     public int getCount() {  
  55.         return list.size();  
  56.     }  
  57.   
  58.     @Override  
  59.     public Object getItem(int arg0) {  
  60.         return arg0;  
  61.     }  
  62.   
  63.     @Override  
  64.     public long getItemId(int arg0) {  
  65.         return arg0;  
  66.     }  
  67.   
  68.     @Override  
  69.     public View getView(int position, View convertView, ViewGroup parent) {  
  70.         ViewHolder holder = null;  
  71.         View vi = convertView;  
  72.         if (convertView == null) {  
  73.             inflater = LayoutInflater.from(mContext);  
  74.             vi = inflater.inflate(R.layout.activity_myread_listview_item, null);  
  75.             holder.titleTextView = (TextView) vi  
  76.                     .findViewById(R.id.iv_book_title);  
  77.             holder.authorTextView = (TextView) vi  
  78.                     .findViewById(R.id.iv_book_author);  
  79.             holder.summeryTextView = (TextView) vi  
  80.                     .findViewById(R.id.iv_book_summary);  
  81.             holder.bookImageView = (ImageView) vi.findViewById(R.id.img1);  
  82.         } else {  
  83.             holder = (ViewHolder) convertView.getTag();  
  84.         }  
  85.         holder.titleTextView.setText(list.get(position).getTitle());  
  86.         holder.authorTextView.setText(list.get(position).getAuthor());  
  87.         holder.summeryTextView.setText(list.get(position).getSummary());  
  88.         String imageUrl = list.get(position).getBookImageUrl();  
  89.         final String imageName = imageUrl.substring(  
  90.                 imageUrl.lastIndexOf("/") + 1, imageUrl.length());  
  91.         File file = new File(Environment.getExternalStorageDirectory()  
  92.                 .getAbsolutePath() + "/" + imageName);  
  93.         if (file.exists()) {  
  94.             holder.bookImageView.setImageURI(Uri.fromFile(file));  
  95.             System.out.println("使用SD卡缓存图片");  
  96.         } else {  
  97.             class AsyncTaskLoadImage extends AsyncTask<String, Integer, Bitmap> {  
  98.   
  99.                 private ViewHolder holder;  
  100.   
  101.                 public AsyncTaskLoadImage() {  
  102.                     holder=new ViewHolder();  
  103.                 }  
  104.   
  105.                 @Override  
  106.                 protected void onPreExecute() {  
  107.                     super.onPreExecute();  
  108.                 }  
  109.   
  110.                 @Override  
  111.                 protected Bitmap doInBackground(String... params) {  
  112.                     Bitmap bitmap = null;  
  113.                     try {  
  114.                         URL url = new URL(params[0]);  
  115.                         HttpURLConnection urlConnection = (HttpURLConnection) url  
  116.                                 .openConnection();  
  117.                         urlConnection.connect();  
  118.                         int MAX = urlConnection.getContentLength();  
  119.                         InputStream inputStream = urlConnection  
  120.                                 .getInputStream();  
  121.                         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();  
  122.                         byte[] b = new byte[1024];  
  123.                         int len = 0;  
  124.                         while ((len = inputStream.read(b)) != -1) {  
  125.                             byteArrayOutputStream.write(b, 0, len);  
  126.                         }  
  127.                         bitmap = BitmapFactory.decodeByteArray(  
  128.                                 byteArrayOutputStream.toByteArray(), 0, MAX);  
  129.                         inputStream.close();  
  130.                     } catch (MalformedURLException e) {  
  131.                         e.printStackTrace();  
  132.                     } catch (IOException e) {  
  133.                         e.printStackTrace();  
  134.                     }  
  135.                     return bitmap;  
  136.                 }  
  137.   
  138.                 @Override  
  139.                 protected void onPostExecute(Bitmap result) {  
  140.                     super.onPostExecute(result);  
  141.                     holder.bookImageView.setImageBitmap(result);  
  142.                 }  
  143.   
  144.             }  
  145.             AsyncTaskLoadImage asyncTaskLoadImage = new AsyncTaskLoadImage();  
  146.             asyncTaskLoadImage.execute(imageUrl);  
  147.         }  
  148.   
  149.         return vi;  
  150.     }  
  151.   
  152.     public class ViewHolder {  
  153.         TextView titleTextView, authorTextView, summeryTextView;  
  154.         ImageView bookImageView;  
  155.     }  
  156. }  

              在这个自定义Adapter中,使用AsyncTask下载图片,然用一级缓存(保存图片到SD卡)。如果ListView显示的图片之前下载过,那么就从SD卡里面加载显示,不去下载,节省流量。表面上看没什么问题,但是实际使用中就会发现图片错位的现象。那图片为什么会错位呢?问题就在于

[java] view plaincopy
  1. if (convertView == null) {  
  2.                    
  3.         } else {  
  4.             holder = (ViewHolder) convertView.getTag();  
  5.         }  
               重用了convertView导致的。如果你重用了convertView,此时convertView中的ImageView的id值是相等的,而我们在设置ImageView的图片时,是根据id来设置的,此时就出现了图片错位问题。 如果不重用convertView,在这种情况下,图片一般是不会产生错位的。但是你如果真的在使用这种方法来使用getView的话,并且图片量比较大的时候,你程序的性能肯定不会好到哪里去了。因此,重用convertView还是很有必要的。

               那如何解决呢?android为我们提供了setTag()方法。具体做法是:在getView的时候给ViewHolder中的ImageView设置tag,其值为要放置在该ImageView上的图片的url地址。这个tag很重要,在异步下载图片完成回调的方法中,我们使用findViewWithTag(String url)来找到ListView中对应的ImagView,然后给该ImageView设置图片即可。在上面的代码中,就需要加入

[java] view plaincopy
  1. holder.bookImageView.setTag(list.get(position));  
 这段代码就可以了。
原创粉丝点击