博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android异步下载图片的类和缓存图片到SD卡的类。
阅读量:5160 次
发布时间:2019-06-13

本文共 14105 字,大约阅读时间需要 47 分钟。

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

开始自己动手写了。写了一个异步下载图片的类和一个缓存图片到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
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
(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
{ 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
> 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
> 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 @Override20 public int getCount() {21 return list.size();22 }23 24 @Override25 public Object getItem(int position) {26 return list.get(position);27 }28 29 @Override30 public long getItemId(int position) {31 return position;32 }33 34 @Override35 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: getCacheImage119      * @Description: 从SD卡的缓存目录中读取图片120      * @throws 无121      * @param key122      *            图片的URL123      * @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: cacheDirSize152      * @Description: 此方法用来计算文件夹的大小153      * @throws 无154      * @param file155      *            需要计算大小的文件夹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: delete170      * @Description: 此方法用来删除文件夹内的所有文件。171      * @throws 无172      * @param file173      *            需要删除内部所有文件的文件夹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: deleteExternalCacheFile188      * @Description: 删除SD卡缓存文件夹里的所有文件。189      * @throws 无190      */191     public void deleteExternalCacheFile() {192         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {193             delete(getExternalCacheDir());194         }195     }196 197     /**198      * 199      * @Method: deleteCacheFile200      * @Description: 删除程序安装目录下的缓存文件夹里所有文件。201      * @throws 无202      */203     public void deleteCacheFile() {204         File cacheFile = context.getCacheDir();205         delete(cacheFile);206     }207 }

 

 

 

 

转载于:https://www.cnblogs.com/zhengxt/p/3634979.html

你可能感兴趣的文章
SQL 一些语句记录
查看>>
开发工作时间及内容 (一)
查看>>
ubuntu配置jdk7.0过程
查看>>
解析java泛型(二)
查看>>
mockito static method wiki
查看>>
Tomcat笔记:Tomcat的执行流程解析
查看>>
软件工程网络15个人阅读作业1(201521123045 郑子熙)
查看>>
plist中可能会用到的key
查看>>
Codeforces 343D 线段树
查看>>
亮相SIGGRAPH 太极拳三维教学App制作揭秘
查看>>
7-6
查看>>
Codeforces Round #434 D
查看>>
A星寻路demo
查看>>
HDU 1260
查看>>
I-team 博客的 gitlab-runner 持续集成实践
查看>>
数据的双向绑定 Angular JS之开端篇
查看>>
JavaScript定时器的开启关闭
查看>>
L1-044 稳赢
查看>>
codeforces 1076E Vasya and a Tree 【dfs+树状数组】
查看>>
class 10 文件和异常
查看>>