美文网首页关于Android开发的那些事儿图片Android知识
路边跌倒的老太太我都不服,图片加载我只服Glide

路边跌倒的老太太我都不服,图片加载我只服Glide

作者: Bear_android | 来源:发表于2017-02-10 16:34 被阅读344次

    泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech。这个库被广泛的运用在google的开源项目中,包括2014年google I/O大会上发布的官方app。

    相信现在的App上面或多或少都会涉及到图片加载,从最初自己编写http请求下载,到各种第三方的库的使用。可谓是八仙过海各显神通,看到有很多博友对现有的库进行了对比,其中Picasso与Glide对比参照了一下,根据现有项目需求便选择了Glide。

    Glide的特点

    1. 区别于其它的第三方加载库,它可以与activity、fragment的生命周期绑定,在Paused暂停加载,在Resumed的时候又自动重新加载。
    2. 支持Memory和Disk图片缓存
    3. 支持Gif和Webp格式图片
    4. 使用Bitmap Pool可以使Bitmap复用
    5. 对于回收的Bitmap会自动调用recycle,减少系统回收压力

    总体设计

    基本概念

    • RequestManager:请求管理,每一个Activity都会创建一个RequestManager,根据对应Activity的生命周期管理该Activity上所有的图片请求
    • Engine:加载图片的引擎,根据Request创建EngineJob和DecodeJob
    • EngineJob:图片加载
    • DecodeJob:图片处理

    核心类介绍

    3.1 glide

    用于保存整个框架中的配置。
    重要方法:

     public static RequestManager with(Context context) {
            RequestManagerRetriever retriever = RequestManagerRetriever.get();
            return retriever.get(context);
        }
    

    用于创建RequsetManager,这里是Glide通过Activity/Fragment生命周期管理Request的原理所在,整个类很关键,主要原理是创建一个自定义的Fragment,然后通过自定义Fragment生命周期操作RequestManager,从而达到管理request。


    这里会将RequestManagerFragment生命周期事件回调通过RequestManager的构造函数传值。所以RequestManage就能响应RequestManagerFragment的生命周期

    3.2 RequestManagerRetriever

     RequestManager supportFragmentGet(Context context, FragmentManager fm) {
            SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
            RequestManager requestManager = current.getRequestManager();
            if (requestManager == null) {
                requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
                current.setRequestManager(requestManager);
            }
            return requestManager;
        }
    

    这里判断当前RequestManagerFragment是否存在RequestManager,保证一个Activity对应一个RequestManager, 这样有利于管理一个Activity上所有的Request。创建RequestManager的时候会将RequestManagerFragment中的回调接口赋值给RequestManager,达到RequestManager监听RequestManagerFragment的生命周期。

    3.3 RequestManager

    成员变量:

    1. Lifecycle lifecycle,用于监听RequestManagerFragment生命周期。
    2. RequestTracker requestTracker, 用于保存当前RequestManager所有的请求和带处理的请求。
      重要方法:
    /**
         * Lifecycle callback that registers for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
         * permission is present) and restarts failed or paused requests.
         */
        @Override
        public void onStart() {
            // onStart might not be called because this object may be created after the fragment/activity's onStart method.
            resumeRequests();
        }
    
        /**
         * Lifecycle callback that unregisters for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
         * permission is present) and pauses in progress loads.
         */
        @Override
        public void onStop() {
            pauseRequests();
        }
    
        /**
         * Lifecycle callback that cancels all in progress requests and clears and recycles resources for all completed
         * requests.
         */
        @Override
        public void onDestroy() {
            requestTracker.clearRequests();
        }
        ....
            /**
         * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory}s currently
         * registered for the given model class for {@link InputStream}s and {@link ParcelFileDescriptor}s to load a
         * thumbnail from either the image or the video represented by the given model.
         *
         * <p>
         *     Note - for maximum efficiency, consider using {@link #from(Class)}} to avoid repeatedly allocating builder
         *     objects.
         * </p>
         *
         * @see #from(Class)
         *
         * @param model The model the load.
         * @param <T> The type of the model to load.
         */
        public <T> DrawableTypeRequest<T> load(T model) {
            return (DrawableTypeRequest<T>) loadGeneric(getSafeClass(model)).load(model);
        }
        .........
        public <Y extends Target<TranscodeType>> Y into(Y target) {
        ...
        Request previous = target.getRequest();
        //停止当前target中的Request。
        if (previous != null) {
            previous.clear(); //这个地方很关键,见Request解析
            requestTracker.removeRequest(previous);
            previous.recycle();
        }
        ...
        return target;
       }
     
    

    3.4 DrawableRequestBuilder

    用于创建Request。 这里面包括很多方法,主要是配置加载图片的url、大小、动画、ImageView对象、自定义图片处理接口等。

    3.5 Request

    主要是操作请求,方法都很简单。

       @Override
     public void clear() {
        ...
        if (resource != null) {
            //这里会释放资源
            releaseResource(resource);
        }
        ...
     }
    
    

    这里的基本原理是当有Target使用Resource(Resource见下文)时,Resource中的引用记数值会加一,当释放资源Resource中的引用记数值减一。当没有Target使用的时候就会释放资源,放进Lrucache中。

    3.7 EngineResource

    实现Resource接口,使用装饰模式,里面包含实际的Resource对象

      1. void release() {
      2.    if (--acquired == 0) {
      3.        listener.onResourceReleased(key, this);
      4.    }
      5. }  
      6.  
      7. void acquire() {
      8.    ++acquired;
      9. }  
      10.  
      11. @Override
      12. public void recycle() {
      13.   isRecycled = true;
      14.   resource.recycle();
      15. }
    

    acquire和release两个方法是对资源引用计数;recycle释放资源,一般在Lrucache饱和时会触发。

    3.8 Engine(重要)

    请求引擎,主要做请求的开始的初始化。

    3.8.1 load方法

    这个方法很长,将分为几步分析

    获取MemoryCache中缓存

    首先创建当前Request的缓存key,通过key值从MemoryCache中获取缓存,判断缓存是否存在。

      1. private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
      2.    ....
      3.    EngineResource<?> cached = getEngineResourceFromCache(key);
      4.    if (cached != null) {
      5.        cached.acquire();
      6.        activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
      7.    }
      8.    return cached;
      9. }
      10.  
      11. @SuppressWarnings("unchecked")
      12. private EngineResource<?> getEngineResourceFromCache(Key key) {
      13.   Resource<?> cached = cache.remove(key);
      14.  
      15.   final EngineResource result;
      16.   ...
      17.   return result;
      18. }
    

    (重点)从缓存中获取的时候使用的cache.remove(key),然后将值保存在activeResources中,然后将Resource的引用计数加一。
    优点:

    正使用的Resource将会在activeResources中,不会出现在cache中,当MemoryCache中缓存饱和的时候或者系统内存不足的时候,清理Bitmap可以直接调用recycle,不用考虑Bitmap正在使用导致异常,加快系统的回收。


    获取activeResources中缓存

    activeResources通过弱引用保存recouse ,也是通过key获取缓存,

      1. private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable)
    

    判断当前的请求任务是否已经存在
      1. EngineJob current = jobs.get(key);
      2. if (current != null) {
      3.    current.addCallback(cb);
      4.    return new LoadStatus(cb, current);
      5. }
    

    如果任务请求已经存在,直接将回调事件传递给已经存在的EngineJob,用于请求成功后触发回调。


    执行请求任务
      1. EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
      2. DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
      3.        transcoder, diskCacheProvider, diskCacheStrategy, priority);
      4. EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
      5. jobs.put(key, engineJob);
      6. engineJob.addCallback(cb);
      7. engineJob.start(runnable);
    

    3.9 EngineRunnable

    请求执行Runnable,主要功能请求资源、处理资源、缓存资源。

      1. private Resource<?> decodeFromCache() throws Exception {
      2.    Resource<?> result = null;
      3.    try {
      4.        result = decodeJob.decodeResultFromCache();
      5.    } catch (Exception e) {
      6.        if (Log.isLoggable(TAG, Log.DEBUG)) {
      7.            Log.d(TAG, "Exception decoding result from cache: " + e);
      8.        }
      9.    }
      10.  
      11.   if (result == null) {
      12.       result = decodeJob.decodeSourceFromCache();
      13.   }
      14.   return result;
      15. }  
      16.  
      17. private Resource<?> decodeFromSource() throws Exception {
      18.   return decodeJob.decodeFromSource();
      19. }
    

    加载DiskCache和网络资源。加载DiskCache包括两个,因为Glide默认是保存处理后的资源(压缩和裁剪后),缓存方式可以自定义配置。如果客户端规范设计,ImageView大小大部分相同可以节省图片加载时间和Disk资源。

    3.10 DecodeJob

     public Resource<Z> decodeResultFromCache() throws Exception  
     public Resource<Z> decodeSourceFromCache() throws Exception
    从缓存中获取处理后的资源。上面有关Key的内容,Key是一个对象,可以获取key和orginKey。decodeResultFromCache就是通过key获取缓存,decodeSourceFromCache()就是通过orginKey获取缓存。
     private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded)
    处理和包装资源;缓存资源。
     //保存原资源
     private Resource<T> cacheAndDecodeSourceData(A data) throws IOException  
     //保存处理后的资源
     private void writeTransformedToCache(Resource<T> transformed)
    

    3.11 Transformation

      1. Resource<T> transform(Resource<T> resource, int outWidth, int outHeight);
    

    处理资源,这里面出现BitmapPool类,达到Bitmap复用。

    3.12 ResourceDecoder

    用于将文件、IO流转化为Resource

    3.13BitmapPool

    用于存放从LruCache中remove的Bitmap, 用于后面创建Bitmap时候的重复利用。

    Glide使用

    由于篇幅过长,请点我查看具体使用

    其它

    本文参考地址:http://m.blog.csdn.net/article/details?id=49514465

    相关文章

      网友评论

        本文标题:路边跌倒的老太太我都不服,图片加载我只服Glide

        本文链接:https://www.haomeiwen.com/subject/znrgittx.html