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