非常轻量级的ImageLoader
来源:互联网 发布:matlab向量组成矩阵 编辑:程序博客网 时间:2024/05/29 19:17
非常轻量级的ImageLoader
@(Android)[工具类]
又要开始重复造轮子了,这篇主要是参照郭霖大神的 Android照片墙完整版,完美结合LruCache和DiskLruCache ,和很久以前再慕课网看的一个高效使用ListView教程,然后自己使用DiskLruCache和LruCache写了一个超级轻量级得ImageLoader,有多轻量级呢?以后加载图片只需要一句话:
imageloader.loadBitmap(imgUrl, imageview);
并且 ImageLoader只用来记载图片,并有自带缓存功能。既然说得这么屌,就上代码吧!
先看一下工程:
ImageLoader主要就是一个Java文件,但是由于用到了DiskLruCache,所以需要将其添加进来。引入 DiskLruCache 也相当简单,就是把 DiskLruCache.java 文件放在src的 libcore.io
包下就行了,上面工程截图可以看看。
方便大家下载 DiskLruCache,这里贴一下下载地址:
http://download.csdn.net/detail/sinyu890807/7709759
ImageLoader.java
public class Imageloader { public static final int MAX_DISK_CACHE_SIZE = 10 * 1024 * 1024; private LruCache<String, Bitmap> mMemoryCache; private DiskLruCache mDiskLruCache; private Set<BitmapWorkerTask> mTasks; public Imageloader(Context context) { int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; File cacheDir = new File(getDiskCacheDir(context, "img_thumb")); if (!cacheDir.exists()) { cacheDir.mkdirs(); } try { mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, MAX_DISK_CACHE_SIZE); } catch (IOException e) { e.printStackTrace(); } mTasks = new HashSet<>(); } public String getDiskCacheDir(Context context, String uniqueName) { String cacheDir; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { cacheDir = context.getExternalCacheDir().getPath(); } else { cacheDir = context.getCacheDir().getPath(); } return cacheDir; } public int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return info.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return 1; } public void loadBitmap(String imgUrl, ImageView imageView) { Bitmap bitmap = getBitmapFromMemoryCache(imgUrl); if (null != bitmap && null != imageView) { imageView.setImageBitmap(bitmap); return; } BitmapWorkerTask task = new BitmapWorkerTask(imageView); mTasks.add(task); task.execute(imgUrl); } public void cancelAllTasks() { for (AsyncTask task : mTasks) { task.cancel(false); } } public void flushCache() { if (mDiskLruCache != null) { try { mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } } private void addBitmapToMemoryCache(String imgUrl, Bitmap bitmap) { if (null == mMemoryCache.get(imgUrl)) { mMemoryCache.put(imgUrl, bitmap); } } private Bitmap getBitmapFromMemoryCache(String imgUrl) { return mMemoryCache.get(imgUrl); } class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { private String imgUrl; private ImageView imageView; public BitmapWorkerTask(ImageView imageView) { this.imageView = imageView; } @Override protected Bitmap doInBackground(String... params) { imgUrl = params[0]; FileDescriptor fileDescriptor = null; FileInputStream fis = null; DiskLruCache.Snapshot snapshot = null; try { String key = hashKeyForDisk(imgUrl); snapshot = mDiskLruCache.get(key); if (null == snapshot) { DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { OutputStream os = editor.newOutputStream(0); if (downloadUrlStream(imgUrl, os)) { editor.commit(); } else { editor.abort(); } } } snapshot = mDiskLruCache.get(key); if (null != snapshot) { fis = (FileInputStream) snapshot.getInputStream(0); fileDescriptor = fis.getFD(); } Bitmap bitmap = null; if (null != fileDescriptor) { bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor); } if (bitmap != null) { addBitmapToMemoryCache(imgUrl, bitmap); } return bitmap; } catch (IOException e) { e.printStackTrace(); } finally { if (null != fis) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (null != imageView && null != bitmap) { imageView.setImageBitmap(bitmap); } mTasks.remove(this); } } public String hashKeyForDisk(String key) { String cacheKey; try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(key.getBytes()); cacheKey = byteToHexString(digest.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private String byteToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } private boolean downloadUrlStream(String urlStr, OutputStream outputStream) { HttpURLConnection connection = null; BufferedOutputStream bos = null; BufferedInputStream bis = null; InputStream is = null; try { URL url = new URL(urlStr); connection = (HttpURLConnection) url.openConnection(); bis = new BufferedInputStream(connection.getInputStream()); bos = new BufferedOutputStream(outputStream); byte[] buffer = new byte[1024]; int len = 0; while ((len = bis.read(buffer)) > 0) { bos.write(buffer, 0, len); } return true; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bis != null) { bis.close(); } if (bos != null) { bos.close(); } } catch (IOException e) { e.printStackTrace(); } } return false; }}
代码挺长的,主要看几个东西:
1. loadBitmap(String imgUrl, ImageView imageView)
public void loadBitmap(String imgUrl, ImageView imageView) { //从缓存中取bitmap Bitmap bitmap = getBitmapFromMemoryCache(imgUrl); //如果取到,直接设置给imageview if (null != bitmap && null != imageView) { imageView.setImageBitmap(bitmap); return; } //未取到,则启动task取下载 BitmapWorkerTask task = new BitmapWorkerTask(imageView); mTasks.add(task); task.execute(imgUrl); }
BitmapWorkerTask
主要完成工作就是取下载图片,并且将其缓存到DiskLruCache中。使用的key是 imgUrl 的 MD5 编码。
最主要的就是上面两个内容,其中还设计了 LruCache 和 DiskLruCache的使用,大家自己找文章看看呗
使用方法
这里我们用ListView为例子,假设现在我们有一个这样一个实体类:
public class News { private String name; private String picSmall; private String picBig; private String description; private int learnerCount; public News(String name, String picSmall, String picBig, String description, int learnerCount) { this.name = name; this.picSmall = picSmall; this.picBig = picBig; this.description = description; this.learnerCount = learnerCount; }//....}
我们已经从网络上获取到了一个List<News> data
的数据,现在我们要将数据用 ListView 来显示:
mListView.setAdapter(new NewsAdapter(MainActivity.this, data, mListView));
我们自定义的Adapter的 getView()
方法应该是这样, 加载图片只用了一行代码:
imageloader.loadBitmap(data.get(position).getPicSmall(), holder.smallpic);
@Override public View getView(int position, View convertView, ViewGroup father) { ViewHolder holder = null; if (convertView != null) { holder = (ViewHolder) convertView.getTag(); } else { convertView = this.inflater.inflate(R.layout.news_layout, null, false); holder = new ViewHolder(); holder.smallpic = (ImageView) convertView.findViewById(R.id.iv_smallpic); holder.desc = (TextView) convertView.findViewById(R.id.tv_desc); holder.name = (TextView) convertView.findViewById(R.id.tv_name); holder.learner = (TextView) convertView.findViewById(R.id.tv_leaner); convertView.setTag(holder); } holder.smallpic.setImageResource(R.mipmap.ic_launcher); holder.name.setText(this.data.get(position).getName()); holder.desc.setText(this.data.get(position).getDescription()); holder.learner.setText("" + this.data.get(position).getLearnerCount()); //使用Imageloader加载图片 imageloader.loadBitmap(data.get(position).getPicSmall(), holder.smallpic); return convertView; }
轻松搞定,并且ImageLoader已经做了缓存,下次打开应用,没有网络的情况下同样可以访问图片。
当然,这样加载是一次加载 ListView的 所有 item,肯定是不对的。正确的是 ListView 滑动到哪里,就显示哪里。郭霖大神博客中有提到,大家可以自己看看。
整个工程
为了让大家看明白,这里附上整个工程代码,可以细细品味一下:
http://download.csdn.net/detail/u013647382/9607106
- 非常轻量级的ImageLoader
- imageLoader的轻量级实现
- 非常出色的轻量级 JavaScript 库
- 一个非常轻量级自定义的HUD
- httpsqs 非常小的轻量级消息队列服务
- [安卓自定义类库]写一个自己的轻量级ImageLoader——LightImageLoader
- 收集的一些轻量级非常实用的前端开发小工具
- Imageloader<5>-ImageLoader的变量初始化
- ImageLoader源码解析-----ImageLoader的结构
- ImageLoader的使用
- ImageLoader的使用
- 开源库ImageLoader的使用
- ImageLoader遇到的问题
- ImageLoader的用法
- ImageLoader的基本使用
- ImageLoader的基本使用方法
- ImageLoader的使用
- 图片的加载ImageLoader
- iOS复杂动画之抽丝剥茧(Objective-C & Swift)
- 转一个quaternion基础的
- 【转】Android:LinearLayout布局中Layout_weight的深刻理解
- ConcurrentHashMap使用要点
- fragment详解
- 非常轻量级的ImageLoader
- this 指针
- poj 1019Number Sequence(数学 巧妙~~~)
- wpf 颜色渐变的圆
- java特性之自动拆装箱
- Map、Set、List部分总结
- == 与 equals的区别
- php中self 、parent的用法
- 2016多校训练Contest10: 1002 Hard problem hdu5858