非常轻量级的ImageLoader

非常轻量级的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);
    }
  1. 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值