Glide学习笔记

作者: Coder_Sven | 来源:发表于2020-06-22 14:00 被阅读0次

    默认情况下,Glide会在开始一个新的图片请求(网络请求)之前检查以下多级缓存

    1. 活动资源 (Active Resources) 
    2. 内存缓存 (Memory Cache) 
    3. 资源类型(Resource Disk Cache)
    4. 原始数据 (Data Disk Cache)
    活动资源:如果当前对应的图片资源正在使用,则这个图片会被Glide放入活动缓存。
    内存缓存:如果图片最近被加载过,并且当前没有使用这个图片,则会被放入内存中
    资源类型:  被解码后的图片写入磁盘文件中,解码的过程可能修改了图片的参数(如:inSampleSize、inPreferredConfig)
    原始数据:  图片原始数据在磁盘中的缓存(从网络、文件中直接获得的原始数据)
    

    在调用Glide.with(activity) .load(url) .into(imageView)时,Glide会首先从Active Resources查找当前是否有对应的活跃图片,没有则查找内存缓存,没有则查找资源类型,没有则查找原始数据。


    11462765-5ad875863445b4f1.webp.jpg

    第一层 活动资源

    活动资源是一个“引用计数”的图片资源的弱引用集合。

    因为同一张图片可能在多个地方被同时使用,每一次使用都会将引用计数+1,而当引用计数为0时候,则表示这个图片没有被使用也就是没有强引用了。这样则会将图片从活动资源中移除,并加入内存缓存。

    /**
     * 引用计数为0回调
     * 将其从正在使用集合移除 并加入内存缓存
      * @param key
     * @param resource
     */
    @Override
    public void onResourceReleased(Key key, Resource resource) {
        activeResource.deactivete(key);
        Glide.get(context).getBitmapPool().put(resource.getBitmap());
    }
    

    第二层 内存缓存

    内存缓存默认使用LRU(最近最少使用算法),当资源从活动资源移除的时候,会加入此缓存。使用图片的时候会主动从此缓存移除,加入活动资源。

    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        } else {
            this.maxSize = maxSize;
            this.map = new LinkedHashMap(0, 0.75F, true);
        }
    }
    

    LinkedHashMap的第三个参数为true,开启自动排序,在使用此map进行get或者put的时候会自动排序,确保了最近最少使用的在尾端最先被删除。

    第三,四层 磁盘缓存

    Resource缓存的是经过解码后的图片。

    Data缓存的则是图像原始数据。同样都是维护了一个LRU的算法

    Bitmap复用

    如果缓存都不存在,那么会从源地址获得图片(网络/文件)。而在解析图片的时候会需要BitmapPool(复用池),达到复用的效果


    11462765-4ae3a04cdd66d3ac.webp.jpg 11462765-31d71dbda64060b2.webp.jpg

    复用效果如上。在未使用复用的情况下,每张图片都需要一块内存。而使用复用的时候,如果存在能被复用的图片会重复使用该图片的内存。
    所以复用并不能减少程序正在使用的内存大小。Bitmap复用,解决的是减少频繁申请内存带来的性能(抖动、碎片)问题。

    BitmapPool是Glide中的Bitmap复用池,同样适用LRU来进行管理。
    当一个Bitmap从内存缓存 被动 的被移除(内存紧张、达到maxSize)的时候并不会被recycle。而是加入这个BitmapPool,只有从这个BitmapPool 被动被移除的时候,Bitmap的内存才会真正被recycle释放。

    网络加载

    资源来源可能有url网络下载,也可能是sd卡中资源加载。根据来源不同来分别使用对应的方式进行加载最终获取得到inputstream流,再通过解码器解码inputstream来得到Bitmap。采用了策略模式,工厂模式,建造者模式根据不同的URI来生产对应的加载器。解析出来的图片资源会存入磁盘缓存,然后再存入到活动资源中!

    生命周期管理

    Glide生命周期绑定是从入口单例类Glide开始的,通过with()多个重载方法来实现对生命周期的绑定工作。

    public static RequestManager with(Fragment fragment)  
    public static RequestManager with(FragmentActivity activity)  
    public static RequestManager with(Activity activity)  
    public static RequestManager with(Context context)
    

    以Activity的参数为例:

    public static RequestManager with(Activity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
    

    RequestManagerRetriever是一个单例类,可以理解为一个工厂类,通过get方法接收不同的参数,来创建RequestManager。

    public RequestManager get(Activity activity) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            android.app.FragmentManager fm = activity.getFragmentManager();
            return fragmentGet(activity, fm);
        }
    }
    public RequestManager get(android.app.Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            android.app.FragmentManager fm = fragment.getChildFragmentManager();
            return fragmentGet(fragment.getActivity(), fm);
        }
    }
    

    如果是在子线程进行的with操作,那么Glide将默认使用ApplicationContext,可以理解为不对请求的生命周期进行管理,通过Activity拿到FragmentManager,并将创建RequestManager的任务传递下去。最终都走到了fragmentGet方法,注意细微区别是Activity传的参数的是Activity的FragmentManager,Fragment传的参数的是ChildFragmentManager,这两者不是一个东西。

    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
        //获取RequestManagerFragment,并获取绑定到这个fragment的RequestManager
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
        //如果获取RequestManagerFragment还没有绑定过RequestManager,那么就创建RequestManager并绑定到RequestManagerFragment
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }
    

    创建RequestManagerFragment

    这个方法创建了一个fragment,并且创建并绑定了一个RequestManager,看看getRequestManagerFragment如何获取的RequestManagerFragment。

    RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
        //尝试根据id去找到此前创建的RequestManagerFragment
        RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
            //如果没有找到,那么从临时存储中寻找
            current = pendingRequestManagerFragments.get(fm);
            if (current == null) {
                //如果仍然没有找到,那么新建一个RequestManagerFragment,并添加到临时存储中。
                //然后开启事务绑定fragment并使用handler发送消息来将临时存储的fragment移除。
                current = new RequestManagerFragment();
                pendingRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }
    

    接着往下看RequestManagerFragment的构造方法做了什么。

    public RequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
    }
    

    直接创建一个ActivityFragmentLifecycle,这个类实际是一个生命周期回调的管理类,实现了Lifecycle接口。所有的LifecycleListener会添加到一个集合中,当RequestManagerFragment生命周期方法触发时,会调用ActivityFragmentLifecycle相应生命周期方法,这个方法然后再遍历调用所有LifecycleListener的生命周期方法,以onStart生命周期方法为例,RequestManagerFragment中:

    public void onStart() {
        super.onStart(); 
        lifecycle.onStart();
    }
    

    然后ActivityFragmentLifecycle中:

    void onStart() {
        isStarted = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onStart();
        }
    }
    

    rootRequestManagerFragment

    RequestManagerFragment还有一个rootRequestManagerFragment的成员变量,Glide每创建一个RequestManagerFragment,都会尝试实例化rootRequestManagerFragment,这个fragment即顶级的Activity所创建的RequestManagerFragment,相关代码:

    public void onAttach(Activity activity) {
        super.onAttach(activity);
        rootRequestManagerFragment = RequestManagerRetriever.get()
                .getRequestManagerFragment(getActivity().getFragmentManager());
        if (rootRequestManagerFragment != this) {
            rootRequestManagerFragment.addChildRequestManagerFragment(this);
        }
    }
    
    @Override
    public void onDetach() {
        super.onDetach();
        if (rootRequestManagerFragment != null) {
            rootRequestManagerFragment.removeChildRequestManagerFragment(this);
            rootRequestManagerFragment = null;
        }
    }
    

    可以看到,不管当前的RequestManagerFragment是通过何种方式创建的,都会在OnAttach时,拿到当前所绑定的Activity的FragmentManager来初始化一个RequestManagerFragment,这个RequestManagerFragment有可能是自身,有可能已经被初始化过了,比如是通过with(Activity activity)的方式初始化的,那么很显然

    RequestManagerRetriever.get().getRequestManagerFragment(getActivity().getFragmentManager());
    

    这句代码拿到的会是自己本身,而如果是通过with(Fragment fragment)的形式创建的,rootRequestManagerFragment将指向当前fragment绑定到Activity所绑定的RequestManagerFragment,如果该Activity没有绑定过,那么会开启事务绑定一个RequestManagerFragment。并且如果自己不是rootRequestManagerFragment的话,那么将会把自己保存到rootRequestManagerFragment中的一个集合:

    private void addChildRequestManagerFragment(RequestManagerFragment child) {
        childRequestManagerFragments.add(child);
    }
    

    简而言之,Glide会为Activity创建一个RequestManagerFragment做为rootFragment,并保存该Activity底下所有Fragment(如果有的话)所创建的RequestManagerFragment。

    RequestManagerTreeNode

    RequestManagerFragment初始化时,还会初始化RequestManagerTreeNode,顾名思义,这个类是用来保存请求树节点的,比如一个Activity采用Viewpager + Fragment的形式,而里面的Fragment又是一个ViewPager + Fragment的形式,这个时候,假设其中一个RequestManagerFragment生命周期方法走了,怎么知道哪些RequestManagerFragment绑定的LifeCycle应该得到调用呢?理想的情况是,应该让绑定该RequestManagerFragment的Fragment所有的子Fragment的RequestManagerFragment的生命周期得到调用,比如如下场景中,Activity中各有两个Fragment,两个Fragment又各有两个子Fragment,在所有Fragment中,均通过with(this)的方式来加载图片,经过之前的分析我们可以知道的是,ROOT RMF 中会保存有6个RMF(RMF即RequestManagerFragment):


    11462765-2eec9cc331dad213.webp.jpg

    当如果F1 RMF生命周期做出反应时,因为RequestManagerFragment是无界面的,所以可以理解为F1的生命周期做出反应。我们希望F11和F12所绑定的RequestManagerFragment也要立即做出反应。但是F2以及其底下的RequestManagerFragment则不应响应对应生命周期事件,我们知道任何一个RequestManagerFragment可以通过rootRequestManagerFragment拿到这6个RMF,继而拿到其所对应的RequestManager,那么怎么去确定F11 RMF 和 F12 RMF呢?这就是RequestManagerTreeNode干的事情了,RequestManagerFragment中的非静态内部类FragmentRequestManagerTreeNode实现了RequestManagerTreeNode:

    private class FragmentRequestManagerTreeNode implements RequestManagerTreeNode {
        @Override
        public Set<RequestManager> getDescendants() {
            Set<RequestManagerFragment> descendantFragments = getDescendantRequestManagerFragments();
            HashSet<RequestManager> descendants =
                new HashSet<RequestManager>(descendantFragments.size());
            for (RequestManagerFragment fragment : descendantFragments) {
                if (fragment.getRequestManager() != null) {
                    descendants.add(fragment.getRequestManager());
                }
            }
            return descendants;
        }
    }
    

    这个类做的事情比较简单,调用外部类RequestManagerFragment的方法getDescendantRequestManagerFragments拿到所有的“后裔”Fragment,然后再取出它的RequestManager,然后集合装起来返回,这里的后裔在前面的例子中,指的就是F11 RMF 和 F12 RMF,看看getDescendantRequestManagerFragments是怎么拿到的F11和F12:

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public Set<RequestManagerFragment> getDescendantRequestManagerFragments() {
        //如果自己是rootFragment,那么直接返回childRequestManagerFragments
        if (rootRequestManagerFragment == this) {
            return Collections.unmodifiableSet(childRequestManagerFragments);
        } else if (rootRequestManagerFragment == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            // Pre JB MR1 doesn't allow us to get the parent fragment so we can't introspect hierarchy, so just
            // return an empty set.
            return Collections.emptySet();
        } else {
            HashSet<RequestManagerFragment> descendants = new HashSet<RequestManagerFragment>();
            for (RequestManagerFragment fragment
                    //遍历取出rootFragment中的RMF,并获取到其parentFragment,找出后裔。
                    : rootRequestManagerFragment.getDescendantRequestManagerFragments()) {
                if (isDescendant(fragment.getParentFragment())) {
                    descendants.add(fragment);
                }
            }
            return Collections.unmodifiableSet(descendants);
        }
    }
    

    RequestManager

    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
        //获取RequestManagerFragment,并获取绑定到这个fragment的RequestManager
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
        //如果获取RequestManagerFragment还没有绑定过RequestManager,那么就创建RequestManager并绑定到RequestManagerFragment
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }
    

    RequestManager是一个非常核心的类,并且还实现了LifecycleListener来处理请求的生命周期。上述代码在创建RequestManager时,传递了3个参数,分别是context,前面分析过的初始化RequestManagerFragment所创建的LifeCycle和RequestManagerTreeNode。直接看RequestManager的构造函数:

    public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }
    

    调用的另一个构造方法,并增加了两个新的参数RequestTracker和ConnectivityMonitorFactory。

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
            RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
        this.context = context.getApplicationContext();
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        this.glide = Glide.get(context);
        this.optionsApplier = new OptionsApplier();
    
        ConnectivityMonitor connectivityMonitor = factory.build(context,
                new RequestManagerConnectivityListener(requestTracker));
    
        // If we're the application level request manager, we may be created on a background thread. In that case we
        // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
        // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
        if (Util.isOnBackgroundThread()) {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    lifecycle.addListener(RequestManager.this);
                }
            });
        } else {
            lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    }
    

    RequestTracker即所有请求操作的真正处理者,所有Request的暂停取消执行操作都由RequestTracker来完成,如RequestManager暂停请求的实现:

    public void pauseRequests() {
        Util.assertMainThread();
        requestTracker.pauseRequests();
    }
    

    生命周期回调总结

    在RequestManager构造方法中,还会将自身添加到LifeCycle中,这样,整个流程就畅通了

    11462765-d93ece38acdbfb2a.webp.jpg

    Glide源码分析流程图

    Glide加载原理.jpg

    项目代码:
    https://github.com/games2sven/Glide

    本文转自作者“十年开发程序员”的Glide生命周期管理,如有侵权,请联系作者效效进行修改。

    相关文章

      网友评论

        本文标题:Glide学习笔记

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