探索ImageLoader

图片加载是Android程序中很常用的功能,这篇文章我们简要分析一下ImageLoader的过程


1. Bitmap的高效加载

       Bitmap在Android中指的是一张图片,BitmapFactory提供了四种方法来获取Bitmap,分别是

decodeFile(String    pathName)

decodeResource(R.xxx.xxx)

decodeStream()

decodeByteArray(byte[] bytes)

在获取到图片之后,就要通过ImageView把图片显示出来,但是

ImageView有时候并没有图片那么大,所以就需要通过BitmapFactory.Option按一定的采样率来压缩图片,这样就可以在一定程度长避免OOM,那么什么是采样率呢,

       采样率:inSampleSize, 等于1时处理后的图片等于原图大小

       为2时宽高均压缩为原来的1/2,像素变为1/4,内存变为1/4

那么怎样获取采样率呢


public int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }
        final int height = options.outHeight;
        final int width = options.outWidth;
        Log.d(TAG, "origin, w= " + width + " h=" + height);
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        Log.d(TAG, "sampleSize:" + inSampleSize);
        return inSampleSize;
}

按照上面的方法就可以把图片按照比例缩小了。


2. 缓存策略

a. 内存缓存 LruCache (support-v4包下)

b. 硬盘缓存 DiskLruCache (DiskLruCache)

1)内存缓存 : LruCache

初始化 : 

LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(maxMemory){
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return super.sizeOf(key, value);
    }
};

添加缓存对象 : lruCache.put(key, bitmap);

获取缓存对象 :lruCache.get(key);

其中key为图片url的hasCode值或者MD5值

删除缓存对象 :lruCache.remove(key); 需要重写entryRemoved()方法

2)硬盘缓存 :

       初始化 : diskLruCache= DiskLruCache.open(File directory, int appVersion, int valueCount, longmaxSize);

directory指缓存的文件目录,appVersion指应用的版本号,一般设为1,当版本号发生改变时,之前的缓存会清除,但是一般应用在更新时缓存都还是有效的,所以这个参数一般就设为1

valueCount指单个节点对应的数据个数;

maxSize指缓存的最大值

       添加缓存

       DiskLruCache的缓存添加操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象,通过diskLruCache对象的edit方法来获取

diskLruCache = DiskLruCache.open(diskCacheDir, 1, NODE_COUNT, DISK_SIZE);
String key = hashKeyFromUrl(url);
DiskLruCache.Editor editor = diskLruCache.edit(key);
if(editor != null){
	OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
}

下载文件到输出流

public boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
        HttpURLConnection urlConnection = null;
        BufferedOutputStream out = null;
        BufferedInputStream in = null;

        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(),
                    IO_BUFFER_SIZE);
            out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);

            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
            return true;
        } catch (IOException e) {
            Log.e(TAG, "downloadBitmap failed." + e);
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            MyUtils.close(out);
            MyUtils.close(in);
        }
        return false;
}

提交缓存 : 

if (downloadUrlToStream(url, outputStream)) {
    editor.commit();
} else {
    editor.abort();
}
mDiskLruCache.flush();

查找缓存 : 

Bitmap bitmap ;
String key = hashKeyFromUrl(url);
try {
    DiskLruCache.Snapshot snapshot = diskLruCache.get(key);
    if(snapshot != null){
        FileInputStream inputStream = (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);
        FileDescriptor fileDescriptor = inputStream.getFD();
        bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
        lruCache.put(key, bitmap);
        diskLruCache.remove(key);
    }
} catch (IOException e) {
    e.printStackTrace();
}
 
 

过程和添加过程类似,通过key得到snapShot对象,然后就可以得到文件的输入流了,再通过文件描述来加载bitmap,但是一般加载之前都要经过calculateInSampleSize处理。最后还要把Bitmap添加到LruCache中。

移除缓存 : diskLruCache.remove(key);


3. ImageLoader流程

a. 同步加载/异步加载-----框架

        b. 图片压缩             必要手段

        c. 内存缓存             核心

        d. 硬盘缓存             核心

        e. 网络获取

线程池:在Android中来源于接口Executor,实现类为ThreadPoolExecutor

  corePoolSize:线程池的核心线程数

  maximumPoolSize:最大线程数

  KeepAliveTime:非核心线程的超时时长

  unit:保活时间单位  workQueue:任务队列

  threadFactory:创建新线程





关于ImageLoader的大概过程就是这样~~~~~~


参考资料 :Android开发艺术探索


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值