麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的.
今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了AsynTask这个API,继续这个类,实现起来非常简单也很方便.在doInBackground()方法里实现下载逻辑.具体实现如下
实现逻辑是:先从内存中读取,如果内存中有这张图片,则直接使用;如果内存没有再到sdcard上读取,如果有则显示;如果sdcard上还没有则到网络上读取.内存中开启缓存是参考了网上的实现.麦洛在这里非常感谢喜欢分享的程序猿们.
public class ImageDownloader extends AsyncTask<String, Integer, Object> { private static final String TAG = "ImageDownloader"; // 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动) private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); /** * 显示图片的控件 */ private ImageView mImageView; public ImageDownloader(ImageView image) { mImageView = image; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Object doInBackground(String... params) { // Log.i("ImageDownloader", "loading image..."); String url = params[0]; Drawable drawable = null; try { if (!"".equals(url) && url != null) { String fileName = url.hashCode()+".jpg"; // 如果缓存过就从缓存中取出数据 if (imageCache.containsKey(fileName)) { SoftReference<Drawable> softReference = imageCache.get(fileName); drawable = softReference.get(); if (drawable != null) { return drawable; } } File dir = new File(FileConstant.IMAGE_FILE_PATH); if (!dir.exists()) { boolean m = dir.mkdirs(); } File file = new File(dir, fileName); if (file.exists() && file.length() > 0) { Log.i(TAG, "load image from sd card"); // 如果文件存在则直接读取sdcard drawable = readFromSdcard(file); } else { //file.createNewFile(); Log.i(TAG, "load image from network"); URL imageUrl = new URL(url); // 写入sdcard if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { saveImageFile(imageUrl, file); drawable = Drawable.createFromStream(new FileInputStream(file), fileName); }else{ //直接从流读取 drawable = Drawable.createFromStream(imageUrl.openStream(), fileName); } } if(drawable!=null){ //保存在缓存中 imageCache.put(fileName, new SoftReference<Drawable>(drawable)); } } } catch (Exception e) { e.printStackTrace(); } return drawable; } /** * save image */ private void saveImageFile(URL url, File file) { FileOutputStream out = null; InputStream in = null; try { file.deleteOnExit(); out = new FileOutputStream(file); in = url.openStream(); byte[] buf = new byte[1024]; int len = -1; while((len = in.read(buf))!=-1){ out.write(buf, 0, len); out.flush(); } } catch (Exception e) { e.printStackTrace(); } finally { if(out!=null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if(in!=null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 从sdcard中获取图片 */ private Drawable readFromSdcard(File file) throws Exception { FileInputStream in = new FileInputStream(file); return Drawable.createFromStream(in, file.getName()); } @Override protected void onPostExecute(Object result) { super.onPostExecute(result); Drawable drawable = (Drawable) result; if (mImageView != null && drawable != null) { mImageView.setBackgroundDrawable(drawable); } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } @Override protected void onCancelled() { super.onCancelled(); } }
使用时:
ImageDownloader loader = new ImageDownloader(imageView); loader.execute(url);
其实这样的话,还有一些隐患的,就是说这个类实现还是有些问题的.比如每次都在imageView中设置网络上的图片时,其实是没有使用到这个类里面的内存缓存的,就是imageCache
Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
因为每次设置imageView的时候,都是new了一个ImageDownloader的对象.所以每个ImageDownloader对象里面都是独立的一个imageCache.
另外,AsynTask也是一个线程.而每次使用都开一个线程来load 图片,对线程个数没有进行显示,毕竟线程数目还是有限制的.
所以麦洛今天发现了这个问题,于是参考了别人的实现,使用了线程池,实现逻辑也上面的代码一样,先从内存读取,如果没有到sdcard读取,如果还是没有,则是网络读取;实现没有使用AsynTask,具体代码如下:
/** * 异步加载图片,并将图片设置到ImageView控件中 */ public class ImageDownloader extends AsyncTask<String, Integer, Object> { private static final String TAG = "ImageDownloader"; // 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动) private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); /** * 显示图片的控件 */ private ImageView mImageView; public ImageDownloader(ImageView image) { mImageView = image; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Object doInBackground(String... params) { // Log.i("ImageDownloader", "loading image..."); String url = params[0]; Drawable drawable = null; try { if (!"".equals(url) && url != null) { String fileName = url.hashCode()+".jpg"; // 如果缓存过就从缓存中取出数据 if (imageCache.containsKey(fileName)) { SoftReference<Drawable> softReference = imageCache.get(fileName); drawable = softReference.get(); if (drawable != null) { return drawable; } } File dir = new File(FileConstant.IMAGE_FILE_PATH); if (!dir.exists()) { boolean m = dir.mkdirs(); } File file = new File(dir, fileName); if (file.exists() && file.length() > 0) { Log.i(TAG, "load image from sd card"); // 如果文件存在则直接读取sdcard drawable = readFromSdcard(file); } else { //file.createNewFile(); Log.i(TAG, "load image from network"); URL imageUrl = new URL(url); // 写入sdcard if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { saveImageFile(imageUrl, file); drawable = Drawable.createFromStream(new FileInputStream(file), fileName); }else{ //直接从流读取 drawable = Drawable.createFromStream(imageUrl.openStream(), fileName); } } if(drawable!=null){ //保存在缓存中 imageCache.put(fileName, new SoftReference<Drawable>(drawable)); } } } catch (Exception e) { e.printStackTrace(); } return drawable; } /** * save image */ private void saveImageFile(URL url, File file) { FileOutputStream out = null; InputStream in = null; try { file.deleteOnExit(); out = new FileOutputStream(file); in = url.openStream(); byte[] buf = new byte[1024]; int len = -1; while((len = in.read(buf))!=-1){ out.write(buf, 0, len); out.flush(); } } catch (Exception e) { e.printStackTrace(); } finally { if(out!=null){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if(in!=null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 从sdcard中获取图片 */ private Drawable readFromSdcard(File file) throws Exception { FileInputStream in = new FileInputStream(file); return Drawable.createFromStream(in, file.getName()); } @Override protected void onPostExecute(Object result) { super.onPostExecute(result); Drawable drawable = (Drawable) result; if (mImageView != null && drawable != null) { mImageView.setBackgroundDrawable(drawable); } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } @Override protected void onCancelled() { super.onCancelled(); } }
这个ImageDownloader2的使用也很简单
public class ImageUtil { /** * image loader */ static ImageDownloader2 loader = null; /** * load image */ public static void loadImage(String url,final ImageView imageView){ if(loader == null){ loader = new ImageDownloader2(); } loader.loadDrawable(url, new ImageCallback() { @Override public void imageLoaded(Drawable imageDrawable) { if(imageDrawable!=null){ imageView.setBackgroundDrawable(imageDrawable); } } }); } }
每次在使用是需要调用ImageUtil.loadImage(url,imageView)将图片url已经需要显示图片的控件ImageView的引用传入就可以了.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍Android实现图片缓存与异步加载,包括了Android实现图片缓存与异步加载的使用技巧和注意事项,需要的朋友参考一下 ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom。 Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recyc
本文向大家介绍Android实现图片异步加载及本地缓存,包括了Android实现图片异步加载及本地缓存的使用技巧和注意事项,需要的朋友参考一下 在android项目中访问网络图片是非常普遍性的事情,如果我们每次请求都要访问网络来获取图片,会非常耗费流量,而且图片占用内存空间也比较大,图片过多且不释放的话很容易造成内存溢出。针对上面遇到的两个问题,首先耗费流量我们可以将图片第一次加载上面缓存到本地,
本文向大家介绍Android App中实现图片异步加载的实例分享,包括了Android App中实现图片异步加载的实例分享的使用技巧和注意事项,需要的朋友参考一下 一、概述 一般大量图片的加载,比如GridView实现手机的相册功能,一般会用到LruCache,线程池,任务队列等;那么异步消息处理可以用哪呢? 1、用于UI线程当Bitmap加载完成后更新ImageView 2、在图片加载类初始化时
本文向大家介绍Android实现图片异步加载并缓存到本地,包括了Android实现图片异步加载并缓存到本地的使用技巧和注意事项,需要的朋友参考一下 在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片。 软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地
本文向大家介绍vue异步加载高德地图的实现,包括了vue异步加载高德地图的实现的使用技巧和注意事项,需要的朋友参考一下 本文介绍了vue异步加载高德地图的实现,分享给大家,具体如下: 几种加载js的方式 同步加载 异步加载 延迟加载 同步加载 用的最多的一种方式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作。所以默认同步执行才是安全的。但这样如果js
本文向大家介绍Android实现图片异步请求加三级缓存,包括了Android实现图片异步请求加三级缓存的使用技巧和注意事项,需要的朋友参考一下 使用xUtils等框架是很方便,但今天要用代码实现bitmapUtils 的功能,很简单, AsyncTask请求一张图片 ####AsyncTask #####AsyncTask是线程池+handler的封装 第一个泛型: 传参的参数类型类型(和doIn