zoukankan      html  css  js  c++  java
  • Android异步下载图片的类和缓存图片到SD卡的类。

    最近因为以前写应用的网络图片读取都是另外启动一个线程去下载,现在感觉下载速度太慢了,而且也不方便管理。就打算写一个异步下载的,在网上找了一些大神们的博客看了。

    开始自己动手写了。写了一个异步下载图片的类和一个缓存图片到SD卡的类。

    首先是异步下载图片的类,用Android提供的LruCache来缓存图片非常方便,当使用的缓存接近最大时LruCache会自动释放掉使用次数最少的图片。需要了解LruCache更多的信息可以点这里

      1 /**
      2  * 
      3  * @ClassName ImageDownload
      4  * @Description 异步图片下载类,能异步多线程下载图片,最大为并发5线程。能将下载好的图片缓存在内存和SD卡中,
      5  *              等下次需要的时候就不用再下载,节省流量。
      6  * @author lan4627@gmail.com
      7  * @date 2014-3-27
      8  * @version V1.2
      9  */
     10 public class ImageDownload {
     11     private static final String TAG = ImageDownload.class.getSimpleName();
     12     private Context mContext;
     13     private LruCache<String, Bitmap> mLruCache;
     14     private ImageLoader imageLoader;
     15     private ImageCache imageCache;
     16 
     17     public ImageDownload(Context context) {
     18         mContext = context.getApplicationContext();
     19         // 用最大内存的八分之一来存图片
     20         int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
     21         int cache = maxMemory / 8;
     22         mLruCache = new LruCache<String, Bitmap>(cache) {
     23 
     24             protected int sizeOf(String key, Bitmap value) {
     25                 return (value.getRowBytes() * value.getHeight()) / 1024;
     26             }
     27 
     28         };
     29         // 初始化图片缓存类,用来把图片缓存到SD卡的文件夹里
     30         imageCache = new ImageCache(mContext);
     31     }
     32     
     33     private void addImageCache(String key, Bitmap bitmap) {
     34         if (getImage(key) == null) {
     35             mLruCache.put(key, bitmap);
     36         }
     37     }
     38 
     39     private Bitmap getImage(String key) {
     40         return mLruCache.get(key);
     41     }
     42 
     43     /**
     44      * 
     45      * @Method: loadBitmap
     46      * @Description: 读取图片的方法,先找缓存中看是否有,没有再找SD卡的缓存目录中是否有,没有再启动一个线程去下载图片。
     47      *               下载完成后返回图片,同时把下载好的图片储存在缓存和SD卡中,下次要用就不用再下载了。
     48      * @throws 49      * @param key
     50      *            需要下载的图片的URL
     51      * @param imageLoader
     52      *            回调接口
     53      * @return 返回一个Bitmap类型的图片
     54      */
     55     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     56     public Bitmap loadBitmap(String key, ImageLoader imageLoader) {
     57         Bitmap bitmap = getImage(key);
     58         if (bitmap != null) {
     59             return bitmap;
     60         }
     61         // 读取内置SD卡的缓存文件夹看有没有这张图片
     62         bitmap = imageCache.getCacheImage(key);
     63         if (bitmap != null) {
     64             addImageCache(key, bitmap);
     65             return getImage(key);
     66         }
     67         // 如果都没有,则启动线程去联网读取。
     68         this.imageLoader = imageLoader;
     69         if (android.os.Build.VERSION.SDK_INT > 10) {
     70             new ImageDownloadTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key); // 当SDK版本大于10时,建立一个线程池为5的AsyncTask
     71         } else {
     72             new ImageDownloadTask().execute(key);
     73         }
     74         // 返回一个默认的占位图。
     75         return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bit_null);
     76     }
     77 
     78     public interface ImageLoader {
     79         public void onImage(String key, Bitmap bitmap);
     80     }
     81 
     82     class ImageDownloadTask extends AsyncTask<String, Integer, Bitmap> {
     83         private String key;
     84 
     85         protected Bitmap doInBackground(String... params) {
     86             Bitmap bitmap = null;
     87             InputStream is = null;
     88             try {
     89                 key = params[0];
     90                 URL url = new URL(key);
     91                 HttpURLConnection huc = (HttpURLConnection) url.openConnection();
     92                 // 设置请求方式
     93                 huc.setRequestMethod("GET");
     94                 // 设置读取的超时时间
     95                 huc.setReadTimeout(11000);
     96                 // 设置网络连接超时时间
     97                 huc.setConnectTimeout(4000);
     98                 // 拿到服务器返回的响应码
     99                 int hand = huc.getResponseCode();
    100                 if (hand == 200) {
    101                     // 读取图片
    102                     is = huc.getInputStream();
    103                     bitmap = BitmapFactory.decodeStream(is);
    104                 } else {
    105                     Log.e(TAG, "错误的服务器返回码" + hand);
    106                 }
    107             } catch (ProtocolException e) {
    108                 Log.e(TAG, "不支持的连接方式");
    109                 e.printStackTrace();
    110             } catch (MalformedURLException e) {
    111                 Log.e(TAG, "URL解析错误");
    112                 e.printStackTrace();
    113             } catch (IOException e) {
    114                 Log.e(TAG, "连接打开错误或创建输入流错误");
    115                 e.printStackTrace();
    116             } finally {
    117                 if (is != null) {
    118                     try {
    119                         is.close();
    120                     } catch (IOException e) {
    121                         Log.e(TAG, "InputStream关闭时发生错误");
    122                         e.printStackTrace();
    123                     }
    124                 }
    125             }
    126             if (bitmap != null) {
    127                 // 如果不等于空,则加入缓存中以及保存到SD卡。
    128                 addImageCache(key, bitmap);
    129                 imageCache.saveImage(key, bitmap);
    130             }
    131             return bitmap;
    132         }
    133         // 下载完成后通过实现好的接口设置图片
    134         protected void onPostExecute(Bitmap bitmap) {
    135             if (bitmap != null) {
    136                 imageLoader.onImage(key, bitmap);
    137             }
    138         }
    139 
    140     }
    141 }

    一般都是在GridView和ListView的适配器里使用这个异步下载的工具。

     1 public class Test extends BaseAdapter {
     2     private ArrayList<HashMap<String, Object>> list;
     3     private LayoutInflater lInflater;
     4     private ListView listView;
     5     private ImageDownload imageDownload;
     6 
     7     public final class ListItemView {
     8         public ImageView icon;
     9     }
    10 
    11     public Test(Context context, ArrayList<HashMap<String, Object>> list, ListView listView) {
    12         lInflater = LayoutInflater.from(context);
    13         this.list = list;
    14         this.listView = listView;
    15         // 初始化图片下载类
    16         imageDownload = new ImageDownload(context);
    17     }
    18 
    19     @Override
    20     public int getCount() {
    21         return list.size();
    22     }
    23 
    24     @Override
    25     public Object getItem(int position) {
    26         return list.get(position);
    27     }
    28 
    29     @Override
    30     public long getItemId(int position) {
    31         return position;
    32     }
    33 
    34     @Override
    35     public View getView(int position, View convertView, ViewGroup parent) {
    36         ListItemView listItem = null;
    37         if (convertView == null) {
    38             listItem = new ListItemView();
    39             // 获取listItem视图
    40             convertView = lInflater.inflate(R.layout.list_warinfo, null);
    41             listItem.icon = (ImageView) convertView.findViewById(R.id.get_icon);
    42             convertView.setTag(listItem);
    43         } else {
    44             listItem = (ListItemView) convertView.getTag();
    45         }
    46         // 获得要下载的图片网址
    47         String url = (String)list.get(position).get("url");
    48         // 设置标记
    49         listItem.icon.setTag(url);
    50         // 实现回调接口
    51         ImageLoader imageLoader = new ImageLoader() {
    52             
    53             public void onImage(String key, Bitmap bitmap) {
    54                 ImageView image = (ImageView) listView.findViewWithTag(key);
    55                 if (image != null) {
    56                     image.setImageBitmap(bitmap);
    57                 }
    58             }
    59         };
    60         Bitmap bitmap = imageDownload.loadBitmap(url, imageLoader);
    61         listItem.icon.setImageBitmap(bitmap);
    62         return convertView;
    63     }
    64 
    65 }

    下面是图片缓存类,会如果缓存文件夹过大了会自动清除,而且对外也提供了两个清除缓存文件夹的方法。

      1 /**
      2  * 
      3  * @ClassName ImageCache
      4  * @Description 图片缓存
      5  * @author lan4627@gmail.com
      6  * @date 2014-3-29
      7  * @version V1.0
      8  */
      9 public class ImageCache {
     10     private static final String TAG = ImageCache.class.getSimpleName();
     11     private Context context;
     12 
     13     /**
     14      * 
     15      * @Description: ImageCache初始化的时候会启动一个线程检查两个缓存文件夹的大小。
     16      *               如果SD卡内的缓存文件大于5MB,则自动删除里面的文件。 如果内部的缓存文件大于1MB,则自动删除里面的文件。
     17      * @param context
     18      *            上下文
     19      */
     20     public ImageCache(final Context context) {
     21         this.context = context.getApplicationContext();
     22         new Thread() {
     23             public void run() {
     24                 long externalSize = cacheDirSize(getExternalCacheDir());
     25                 long cacheSize = cacheDirSize(context.getCacheDir());
     26                 float size = Float.valueOf(externalSize) / (1024 * 1024);
     27                 if (size > 5) {
     28                     Log.v(TAG, "开始删除文件");
     29                     delete(getExternalCacheDir());
     30                 }
     31                 size = cacheSize / (1024 * 1024);
     32                 if (size > 1) {
     33                     Log.v(TAG, "开始删除文件");
     34                     delete(context.getCacheDir());
     35                 }
     36             }
     37 
     38         }.start();
     39     }
     40 
     41     /**
     42      * 
     43      * @Method: getCacheFile
     44      * @Description: 此方法用来获取缓存文件夹的路径。
     45      *                   如果SD卡是可用的状态,返回SD卡里的缓存文件夹。如果不可以则返回程序安装目录下的缓存文件夹。
     46      * @throws 47      * @return 返回缓存文件夹的路径。
     48      */
     49     private File getCacheFile() {
     50         File file = null;
     51         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
     52             file = getExternalCacheDir();
     53         } else {
     54             file = context.getCacheDir();
     55         }
     56         return file;
     57     }
     58     /**
     59      * 
     60      * @Method: getExternalCacheDir 
     61      * @Description: 此方法根据不同的SDK版本来返回SD卡内的缓存文件夹路径。
     62      *                  Android2.1以上的版本返回/Android/data/包名/cache。
     63      *                  Android2.1及以下版本在SD卡根目录创建一个ImageCache文件夹。
     64      * @throws 65      * @return 返回SD卡里的缓存文件夹路径。
     66      */
     67     @SuppressLint("NewApi")
     68     private File getExternalCacheDir() {
     69         File file = null;
     70         if (android.os.Build.VERSION.SDK_INT > 7) {
     71             file = context.getExternalCacheDir();
     72         } else {
     73             file = new File(Environment.getExternalStorageDirectory() + "/ImageCache");
     74             // 如果目录不存在就创建一个
     75             if (!file.exists()) {
     76                 file.mkdir();
     77             }
     78         }
     79         return file;
     80     }
     81 
     82     /**
     83      * 
     84      * @Method: saveImage
     85      * @Description: 把下载的图片保存在内置SD卡的缓存文件夹中,下次要用的时候可以先检查缓存的文件夹里有没有,有的话就不用下载
     86      * @throws 87      * @param key
     88      *            图片的URL
     89      * @param bitmap
     90      *            图片
     91      */
     92     public boolean saveImage(String path, Bitmap bitmap) {
     93         // 把图片的下载地址作为保存的名字,需要把/和:替换掉,不然程序会认为这是一个目录。
     94         String fileName = path.replace("/", "_").replace(":", "&");
     95         File saveFile = new File(getCacheFile(), fileName);
     96         FileOutputStream fos = null;
     97         try {
     98             fos = new FileOutputStream(saveFile);
     99             return bitmap.compress(CompressFormat.JPEG, 70, fos);
    100         } catch (FileNotFoundException e) {
    101             Log.e(TAG, "缓存图片的文件夹路径不存在");
    102             return false;
    103         } finally {
    104             if (fos != null) {
    105                 try {
    106                     fos.flush();
    107                     fos.close();
    108                 } catch (IOException e) {
    109                     Log.e(TAG, "写入缓存图片的文件输出流关闭错误");
    110                     e.printStackTrace();
    111                 }
    112             }
    113         }
    114     }
    115 
    116     /**
    117      * 
    118      * @Method: getCacheImage
    119      * @Description: 从SD卡的缓存目录中读取图片
    120      * @throws121      * @param key
    122      *            图片的URL
    123      * @return 返回一个Bitmap类型的图片, 如果缓存文件夹里无此图片则返回null。
    124      */
    125     @SuppressLint("NewApi")
    126     public Bitmap getCacheImage(String path) {
    127         String fileName = path.replace("/", "_").replace(":", "&");
    128         Bitmap bitmap = null;
    129         File cacheFile = new File(getCacheFile(), fileName);
    130         FileInputStream fis = null;
    131         try {
    132             fis = new FileInputStream(cacheFile);
    133             bitmap = BitmapFactory.decodeStream(fis);
    134         } catch (FileNotFoundException e) {
    135             Log.i(TAG, "缓存图片不存在");
    136         } finally {
    137             if (fis != null) {
    138                 try {
    139                     fis.close();
    140                 } catch (IOException e) {
    141                     Log.e(TAG, "读取缓存图片的文件输入流关闭错误");
    142                     e.printStackTrace();
    143                 }
    144             }
    145         }
    146         return bitmap;
    147     }
    148 
    149     /**
    150      * 
    151      * @Method: cacheDirSize
    152      * @Description: 此方法用来计算文件夹的大小
    153      * @throws154      * @param file
    155      *            需要计算大小的文件夹
    156      * @return 返回文件夹大小。一个long类型的数,单位为字节。
    157      */
    158     private long cacheDirSize(File file) {
    159         long size = 0;
    160         String[] files = file.list();
    161         for (int i = 0; i < files.length; i++) {
    162             size += new File(file, files[i]).length();
    163         }
    164         return size;
    165     }
    166 
    167     /**
    168      * 
    169      * @Method: delete
    170      * @Description: 此方法用来删除文件夹内的所有文件。
    171      * @throws172      * @param file
    173      *            需要删除内部所有文件的文件夹
    174      */
    175     private static synchronized void delete(File file) {
    176         if (file != null && file.exists() && file.isDirectory()) {
    177             String[] files = file.list();
    178             for (int i = 0; i < files.length; i++) {
    179                 new File(file, files[i]).delete();
    180             }
    181             Log.v(TAG, "删除完成");
    182         }
    183     }
    184 
    185     /**
    186      * 
    187      * @Method: deleteExternalCacheFile
    188      * @Description: 删除SD卡缓存文件夹里的所有文件。
    189      * @throws190      */
    191     public void deleteExternalCacheFile() {
    192         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    193             delete(getExternalCacheDir());
    194         }
    195     }
    196 
    197     /**
    198      * 
    199      * @Method: deleteCacheFile
    200      * @Description: 删除程序安装目录下的缓存文件夹里所有文件。
    201      * @throws202      */
    203     public void deleteCacheFile() {
    204         File cacheFile = context.getCacheDir();
    205         delete(cacheFile);
    206     }
    207 }
  • 相关阅读:
    leetcode 78. 子集 JAVA
    leetcode 91. 解码方法 JAVA
    leetcode 75. 颜色分类 JAVA
    leetcode 74 搜索二维矩阵 java
    leetcode 84. 柱状图中最大的矩形 JAVA
    last occurance
    first occurance
    classical binary search
    LC.234.Palindrome Linked List
    LC.142. Linked List Cycle II
  • 原文地址:https://www.cnblogs.com/zhengxt/p/3634979.html
Copyright © 2011-2022 走看看