Android 异步图片加载控件

本文介绍了一个解决异步加载图片导致列表混乱问题的自定义控件,通过使用异步加载和图片缓存机制,实现了高效且有序的图片加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

发一个异步图片加载控件。网上也有大把的异步网络加载图片的控件,但是有一个问题,异步加载会造成列表中的图片混乱,因为列表的每一项的View都可能被重用,异步加载的时候多个异步线程引用到了同一个View造成图片加载混乱。该控件解决这个问题: 

Java代码   收藏代码
  1. import java.io.File;  
  2. import java.io.FileOutputStream;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6. import java.net.URL;  
  7. import java.net.URLConnection;  
  8.   
  9. import android.content.Context;  
  10. import android.graphics.Bitmap;  
  11. import android.graphics.BitmapFactory;  
  12. import android.graphics.drawable.Drawable;  
  13. import android.net.Uri;  
  14. import android.os.AsyncTask;  
  15. import android.util.AttributeSet;  
  16. import android.widget.ImageView;  
  17.   
  18. /** 
  19.  * 异步图片控件  
  20.  * 使用:new AsyncImageView().asyncLoadBitmapFromUrl("http://xxxx","缓存路径"){ 
  21.  *  
  22.  * @author gaoomei@gmail.com 
  23.  * @site http://obatu.sinaapp.com 
  24.  * @version 1.0 
  25.  * @2011-12-3 
  26.  */  
  27. public class AsyncImageView extends ImageView {  
  28.   
  29.     /** 
  30.      * 异步task加载器 
  31.      */  
  32.     private AsyncLoadImage mAsyncLoad;  
  33.   
  34.     /** 
  35.      * 下载回来的图片缓存存活时间,单位:秒(s),默认30分钟 
  36.      */  
  37.     private long mCacheLiveTime = 1800;  
  38.   
  39.     public AsyncImageView(Context context) {  
  40.         super(context);  
  41.     }  
  42.   
  43.     public AsyncImageView(Context context, AttributeSet attrs) {  
  44.         super(context, attrs);  
  45.     }  
  46.   
  47.     public AsyncImageView(Context context, AttributeSet attrs, int defStyle) {  
  48.         super(context, attrs, defStyle);  
  49.     }  
  50.   
  51.     /** 
  52.      *  
  53.      */  
  54.     @Override  
  55.     public void setImageDrawable(Drawable drawable) {  
  56.         if (mAsyncLoad != null) {  
  57.             mAsyncLoad.cancel(true);  
  58.             mAsyncLoad = null;  
  59.         }  
  60.         super.setImageDrawable(drawable);  
  61.     }  
  62.   
  63.     /** 
  64.      * 重写下面几个设置图片资源的方法,目地是取消网络加载 
  65.      */  
  66.     @Override  
  67.     public void setImageResource(int resId) {  
  68.         cancelLoad();  
  69.         super.setImageResource(resId);  
  70.     }  
  71.   
  72.     @Override  
  73.     public void setImageURI(Uri uri) {  
  74.         cancelLoad();  
  75.         super.setImageURI(uri);  
  76.     }  
  77.   
  78.     @Override  
  79.     public void setImageBitmap(Bitmap bitmap) {  
  80.         cancelLoad();  
  81.         super.setImageBitmap(bitmap);  
  82.     }  
  83.   
  84.     /** 
  85.      * 取消正在进行的异步task 
  86.      */  
  87.     public void cancelLoad() {  
  88.         if (mAsyncLoad != null) {  
  89.             mAsyncLoad.cancel(true);  
  90.             mAsyncLoad = null;  
  91.         }  
  92.     }  
  93.   
  94.     /** 
  95.      * 设置图片存活时间 
  96.      *  
  97.      * @param second 
  98.      *            存活时间,单位【秒】,如果等于0或null,则不缓存 
  99.      */  
  100.     public void setCacheLiveTime(long second) {  
  101.         if (second == 0) {  
  102.             this.mCacheLiveTime = 0;  
  103.         } else if (second >= 0) {  
  104.             this.mCacheLiveTime = second * 1000;  
  105.         }  
  106.     }  
  107.   
  108.     /** 
  109.      * 从网络异步加载 
  110.      *  
  111.      * @param url 
  112.      * @param saveFileName 
  113.      */  
  114.     public void asyncLoadBitmapFromUrl(String url, String saveFileName) {  
  115.         if (mAsyncLoad != null) {  
  116.             mAsyncLoad.cancel(true);  
  117.         }  
  118.         // AsyncTask不可重用,所以每次重新实例  
  119.         mAsyncLoad = new AsyncLoadImage();  
  120.         mAsyncLoad.execute(url, saveFileName);  
  121.     }  
  122.   
  123.     /** 
  124.      * 异步加载器 
  125.      */  
  126.     private class AsyncLoadImage extends AsyncTask<String, Integer, Bitmap> {  
  127.         /** 
  128.          * 是否取消 
  129.          */  
  130.         private boolean isCancel = false;  
  131.   
  132.         @Override  
  133.         protected Bitmap doInBackground(String... params) {  
  134.             if (isCancel) {  
  135.                 return null;  
  136.             }  
  137.             String url = params[0];  
  138.             String fileName = params[1];  
  139.             try {  
  140.                 return getBitmap(url, fileName);  
  141.             } catch (IOException e) {  
  142.                 e.printStackTrace();  
  143.             }  
  144.             return null;  
  145.         }  
  146.   
  147.         @Override  
  148.         protected void onCancelled() {  
  149.             System.out.println("async load imgae cancel");  
  150.             isCancel = true;  
  151.         }  
  152.   
  153.         @Override  
  154.         protected void onPostExecute(Bitmap result) {  
  155.             if (!isCancel && result != null) {  
  156.                 AsyncImageView.this.setImageBitmap(result);  
  157.             }  
  158.         }  
  159.     }  
  160.   
  161.     /** 
  162.      * 下载图片 
  163.      *  
  164.      * @param urlString 
  165.      *            url下载地址 
  166.      * @param fileName 
  167.      *            缓存文件路径 
  168.      * @throws IOException 
  169.      */  
  170.     private Bitmap getBitmap(String urlString, String fileName)  
  171.             throws IOException {  
  172.         if (fileName == null || fileName.trim().isEmpty()) {  
  173.             InputStream input = getBitmapInputStreamFromUrl(urlString);  
  174.             return BitmapFactory.decodeStream(input);  
  175.         }  
  176.   
  177.         File file = new File(fileName);  
  178.         if (!file.isFile()  
  179.                 || (mCacheLiveTime > 0 && (System.currentTimeMillis()  
  180.                         - file.lastModified() > mCacheLiveTime))) {  
  181.             InputStream input = getBitmapInputStreamFromUrl(urlString);  
  182.             file = saveImage(input, fileName);  
  183.             // 如果文件结构创建失败,则直接从输入流解码图片  
  184.             if (file == null || !file.exists() || !file.canWrite()  
  185.                     || !file.canRead()) {  
  186.                 return BitmapFactory.decodeStream(input);  
  187.             }  
  188.         }  
  189.         return BitmapFactory.decodeFile(file.getAbsolutePath());  
  190.     }  
  191.   
  192.     /** 
  193.      * 下载图片,输入InputStream 
  194.      *  
  195.      * @param urlString 
  196.      * @return 
  197.      * @throws IOException 
  198.      */  
  199.     private InputStream getBitmapInputStreamFromUrl(String urlString)  
  200.             throws IOException {  
  201.         URL url = new URL(urlString);  
  202.         URLConnection connection = url.openConnection();  
  203.         connection.setConnectTimeout(25000);  
  204.         connection.setReadTimeout(90000);  
  205.         return connection.getInputStream();  
  206.     }  
  207.   
  208.     /** 
  209.      * 从输入流保存图片到文件系统 
  210.      *  
  211.      * @param fileName 
  212.      * @param input 
  213.      * @return 
  214.      */  
  215.     private File saveImage(InputStream input, String fileName) {  
  216.         if (fileName.trim().isEmpty() || input == null) {  
  217.             return null;  
  218.         }  
  219.         File file = new File(fileName);  
  220.         OutputStream output = null;  
  221.         try {  
  222.             file.getParentFile().mkdirs();  
  223.             if (file.exists() && file.isFile()) {  
  224.                 file.delete();  
  225.             }  
  226.             if (!file.createNewFile()) {  
  227.                 return null;  
  228.             }  
  229.             output = new FileOutputStream(file);  
  230.             byte[] buffer = new byte[4 * 1024];  
  231.             do {  
  232.                 // 循环读取  
  233.                 int numread = input.read(buffer);  
  234.                 if (numread == -1) {  
  235.                     break;  
  236.                 }  
  237.                 output.write(buffer, 0, numread);  
  238.             } while (true);  
  239.             output.flush();  
  240.         } catch (Exception e) {  
  241.             e.printStackTrace();  
  242.         } finally {  
  243.             try {  
  244.                 output.close();  
  245.             } catch (IOException e) {  
  246.                 e.printStackTrace();  
  247.             } catch (Exception e2) {  
  248.                 e2.printStackTrace();  
  249.             }  
  250.         }  
  251.         return file;  
  252.     }  
  253. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值