• Glide生命周期原理


    本文首发于 vivo互联网技术 微信公众号 
    链接:https://mp.weixin.qq.com/s/uTv44vJFFJI_l6b5YKSXYQ
    作者:连凌能

    Android App中图片的展示是很基本也很重要的一个功能,在Android平台上有很多的图片加载解决方案,但是官方认可的是Glide。Android App的页面是有生命周期的,Glide比较好的一个功能就是具有生命周期管理功能,能够根据页面和APP的生命周期来管理图片的加载和停止,也开放接口供用户在内存紧张时手动进行内存管理。本文重点是生命周期源码的分析,不会从简单的使用着手。

    一、综述

    这是Glide源码分析的第二篇文章,第一篇是《Glide缓存流程》,从资源的获取流程对源码进行分析。本篇会聚焦于生命周期模块的原理。开始之前先思考下面这几个问题:

    • Glide怎么实现页面生命周期?

    • Glide为什么对Fragment做缓存?

    • Glide如何监听网络变化?

    • Glide如何监测内存?

    二、Glide生命周期传递

    先来看with函数的执行, 会构造glide单例,而 

    RequestManagerRetriever在initializeGlide中会进行构造。

    
    // Glide.java
    public static RequestManager with(@NonNull Activity activity) {
       return getRetriever(activity).get(activity);
    }
     
      @NonNull
      private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        // Context could be null for other reasons (ie the user passes in null), but in practice it will
        // only occur due to errors with the Fragment lifecycle.
        Preconditions.checkNotNull(
            context,
            "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
                + "returns null (which usually occurs when getActivity() is called before the Fragment "
                + "is attached or after the Fragment is destroyed).");
        return Glide.get(context).getRequestManagerRetriever();
      }
     
      @NonNull
      public static Glide get(@NonNull Context context) {
        if (glide == null) {
          synchronized (Glide.class) {
            if (glide == null) {
              checkAndInitializeGlide(context);
            }
          }
        }
     
        return glide;
      }
     
      private static void checkAndInitializeGlide(@NonNull Context context) {
        // In the thread running initGlide(), one or more classes may call Glide.get(context).
        // Without this check, those calls could trigger infinite recursion.
        if (isInitializing) {
          throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
              + " use the provided Glide instance instead");
        }
        isInitializing = true;
        initializeGlide(context);
        isInitializing = false;
      }

    构造完成RequestManagerRetriever通过get返回一个 RequestManager, 如果不在主线程,默认会传入 getApplicationContext,也就是不进行生命周期管理:

    • 在getRequestManagerFragment中先查看当前Activity中有没有FRAGMENT_TAG这个标签对应的Fragment,如果有就直接返回

    • 如果没有,会判断pendingRequestManagerFragments中有没有,如果有就返回

    • 如果没有,就会重写new一个,然后放入到pendingRequestManagerFragments中,然后添加到当前Activity,再给Handler发送一条移除的消息

    
    // RequestManagerRetriever.java
     @NonNull
     public RequestManager get(@NonNull Activity activity) {
       if (Util.isOnBackgroundThread()) {
         return get(activity.getApplicationContext());
       } else {
         assertNotDestroyed(activity);
         android.app.FragmentManager fm = activity.getFragmentManager();
         return fragmentGet(
             activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
       }
     }
     
     private RequestManager fragmentGet(@NonNull Context context,
         @NonNull android.app.FragmentManager fm,
         @Nullable android.app.Fragment parentHint,
         boolean isParentVisible) {
       RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
       RequestManager requestManager = current.getRequestManager();
       if (requestManager == null) {
         // TODO(b/27524013): Factor out this Glide.get() call.
         Glide glide = Glide.get(context);
         requestManager =
             factory.build(
                 glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
         current.setRequestManager(requestManager);
       }
       return requestManager;
     }
     
     private RequestManagerFragment getRequestManagerFragment(
         @NonNull final android.app.FragmentManager fm,
         @Nullable android.app.Fragment parentHint,
         boolean isParentVisible) {
       RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
       if (current == null) {
         current = pendingRequestManagerFragments.get(fm);
         if (current == null) {
           current = new RequestManagerFragment();
           current.setParentFragmentHint(parentHint);
           if (isParentVisible) {
             current.getGlideLifecycle().onStart();
           }
           pendingRequestManagerFragments.put(fm, current);
           fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
           handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
         }
       }
       return current;
     }
     
     public boolean handleMessage(Message message) {
       ...
       switch (message.what) {
         case ID_REMOVE_FRAGMENT_MANAGER:
           android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
           key = fm;
           removed = pendingRequestManagerFragments.remove(fm);
           break;
           ...
       }
       ...
     }

    这里面需要注意一个问题,就是如果with()函数中传进来的不是Activity,而是Fragment,那么也会去创建一个没有界面的RequestManagerFragment,而它的父Fragment就是传进来的Fragment。

    上面为什么需要pendingRequestManagerFragments先进行缓存呢?这个放到下面第二个问题中说明。先接着往下看生命周期的传递。

    RequestManagerFragment是一个很重要的类,Glide就是通过它作为生命周期的分发入口,RequestManagerFragment的默认构造函数会实例化一个ActivityFragmentLifecycle,在每个生命周期onStart/onStop/onDestroy中会调用ActivityFragmentLifecycle:

    
    // RequestManagerFragment.java
    public class RequestManagerFragment extends Fragment {
      private static final String TAG = "RMFragment";
      private final ActivityFragmentLifecycle lifecycle;
      @Nullable private RequestManager requestManager;
         
      public RequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
      }
         
      RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = lifecycle;
      }
         
      @Override
      public void onStart() {
        super.onStart();
        lifecycle.onStart();
      }
     
      @Override
      public void onStop() {
        super.onStop();
        lifecycle.onStop();
      }
     
      @Override
      public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
        unregisterFragmentWithRoot();
      }
         
      ...
    }

    RequestManagerFragment里面有一个实例RequestManager,在前面的fragmentGet,RequestManagerFragment拿到以后会尝试获取它的RequestManager,第一次获取肯定是没有,就会重新构造一个, 通过RequestManagerRetriever构造时传入的RequestManagerFactory工厂类实例化一个RequestManager, 把RequestManagerFragment中的ActivityFragmentLifecycle传进去:

    
    // RequestManagerRetriever.java
    public interface RequestManagerFactory {
        @NonNull
        RequestManager build(
            @NonNull Glide glide,
            @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode,
            @NonNull Context context);
      }
     
      private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
        @NonNull
        @Override
        public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
        }
      };

    很明显生命周期的关键就在ActivityFragmentLifecycle, 在RequestManagerFragment中相应生命周期中会回调它,那么猜测它肯定是在里面维护了一个观察者列表,相应事件发生的时候进行通知, 看下它的源码:

    
    // ActivityFragmentLifecycle.java
    class ActivityFragmentLifecycle implements Lifecycle {
      private final Set<LifecycleListener> lifecycleListeners =
          Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
      private boolean isStarted;
      private boolean isDestroyed;
     
      @Override
      public void addListener(@NonNull LifecycleListener listener) {
        lifecycleListeners.add(listener);
     
        if (isDestroyed) {
          listener.onDestroy();
        } else if (isStarted) {
          listener.onStart();
        } else {
          listener.onStop();
        }
      }
     
      @Override
      public void removeListener(@NonNull LifecycleListener listener) {
        lifecycleListeners.remove(listener);
      }
     
      void onStart() {
        isStarted = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onStart();
        }
      }
     
      void onStop() {
        isStarted = false;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onStop();
        }
      }
     
      void onDestroy() {
        isDestroyed = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
          lifecycleListener.onDestroy();
        }
      }
    }

    所以RequestManagerFragment把这个传给RequestManager后,肯定会注册观察者,看一下RequestManager的相关代码,在构造函数里面lifecycle.addListener(this);,把自己注册为观察者:

    
    // RequestManager.java
    public class RequestManager implements LifecycleListener,
        ModelTypes<RequestBuilder<Drawable>> {
      ...
      protected final Glide glide;
      protected final Context context;
      @Synthetic final Lifecycle lifecycle;
      private final RequestTracker requestTracker;
      private final RequestManagerTreeNode treeNode;
      private final TargetTracker targetTracker = new TargetTracker();
      private final Runnable addSelfToLifecycle = new Runnable() {
        @Override
        public void run() {
          lifecycle.addListener(RequestManager.this);
        }
      };
      private final Handler mainHandler = new Handler(Looper.getMainLooper());
      private final ConnectivityMonitor connectivityMonitor;
     
      private RequestOptions requestOptions;
     
      public RequestManager(
          @NonNull Glide glide, @NonNull Lifecycle lifecycle,
          @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
        this(
            glide,
            lifecycle,
            treeNode,
            new RequestTracker(),
            glide.getConnectivityMonitorFactory(),
            context);
      }
     
      // Our usage is safe here.
      @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
      RequestManager(
          Glide glide,
          Lifecycle lifecycle,
          RequestManagerTreeNode treeNode,
          RequestTracker requestTracker,
          ConnectivityMonitorFactory factory,
          Context context) {
        this.glide = glide;
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        this.context = context;
     
        connectivityMonitor =
            factory.build(
                context.getApplicationContext(),
                new RequestManagerConnectivityListener(requestTracker));
     
        if (Util.isOnBackgroundThread()) {
          mainHandler.post(addSelfToLifecycle);
        } else {
          lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
     
        setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
     
        glide.registerRequestManager(this);
      }

    在看下RequestManager对应的生命周期里面, 在这里面分别启动,停止和销毁请求:

    // RequestManager
    @Override
      public void onStart() {
        resumeRequests();
        targetTracker.onStart();
      }
     
      @Override
      public void onStop() {
        pauseRequests();
        targetTracker.onStop();
      }
     
      @Override
      public void onDestroy() {
        targetTracker.onDestroy();
        for (Target<?> target : targetTracker.getAll()) {
          clear(target);
        }
        targetTracker.clear();
        requestTracker.clearRequests();
        lifecycle.removeListener(this);
        lifecycle.removeListener(connectivityMonitor);
        mainHandler.removeCallbacks(addSelfToLifecycle);
        glide.unregisterRequestManager(this);
      }

    三、Glide为什么对Fragment做缓存?

    再贴一次RequestManagerRetriever中获取Fragment的代码,前面留了一个疑问,为什么这里会需要一个pendingRequestManagerFragments对Fragment进行缓存。

    // RequestManagerRetriever.java
      /**
       * Pending adds for RequestManagerFragments.
       */
      @SuppressWarnings("deprecation")
      @VisibleForTesting
      final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments = new HashMap<>();
     
    private RequestManagerFragment getRequestManagerFragment(
          @NonNull final android.app.FragmentManager fm,
          @Nullable android.app.Fragment parentHint,
          boolean isParentVisible) {
        RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
          current = pendingRequestManagerFragments.get(fm);
          if (current == null) {
            current = new RequestManagerFragment();
            current.setParentFragmentHint(parentHint);
            if (isParentVisible) {
              current.getGlideLifecycle().onStart();
            }
            pendingRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
          }
        }
        return current;
      }

    我们看一个情况:

    Glide.with(Context).load(ImageUrl1).into(imageview1); // task1
    Glide.with(Context).load(ImageUrl2).into(imageview2); // task2

    Android开发应该都知道主线程有一个Handler机制,会往消息队列中放消息,通过Looper按顺序取出来执行。那么主线程中的执行顺序和消息队列中的执行顺序关系是什么?看个栗子:

    
    private void start() {
         mHandler = new Handler(getMainLooper());
     
         VLog.i("HandlerRunT", "=========Begin!============");
         mHandler.post(new Runnable() {
             @Override
             public void run() {
                 VLog.i("HandlerRunT", "=========First!============");
             }
         });
         VLog.i("HandlerRunT", "=========Middle!============");
         mHandler.sendMessage(Message.obtain(mHandler, new Runnable() {
             @Override
             public void run() {
                 VLog.i("HandlerRunT", "=========Second!============");
             }
         }));
         VLog.i("HandlerRunT", "=========End!============");
         Next();
     }
     
     private void Next() {
         VLog.i("HandlerRunT", "=========Next Begin!============");
         mHandler.post(new Runnable() {
             @Override
             public void run() {
                 VLog.i("HandlerRunT", "=========Next First!============");
             }
         });
         VLog.i("HandlerRunT", "=========Next Middle!============");
         mHandler.sendMessage(Message.obtain(mHandler, new Runnable() {
             @Override
             public void run() {
                 VLog.i("HandlerRunT", "=========Next Second!============");
             }
         }));
         VLog.i("HandlerRunT", "=========Next End!============");
     }

    在start中打印的顺序和它里面的Handler中的信息哪个先打印?start中handler的信息和Next函数中的信息打印顺序是怎样的?看下打印结果:

    HandlerRunT: =========Begin!============
    HandlerRunT: =========Middle!============
    HandlerRunT: =========End!============
    HandlerRunT: =========Next Begin!============
    HandlerRunT: =========Next Middle!============
    HandlerRunT: =========Next End!============
    HandlerRunT: =========First!============
    HandlerRunT: =========Second!============
    HandlerRunT: =========Next First!============
    HandlerRunT: =========Next Second!============

    Handler中的顺序会在主线程之后,Handler中的消息执行顺序就是队列先进先出。

    上面执行到task1的时候,在下面这两行代码,add操作会往消息队列放一个消息,这里标记为msg1:

    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
    // FragmentManager.java
        public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
            if (!allowStateLoss) {
                checkStateLoss();
            }
            synchronized (this) {
                if (mDestroyed || mHost == null) {
                    if (allowStateLoss) {
                        // This FragmentManager isn't attached, so drop the entire transaction.
                        return;
                    }
                    throw new IllegalStateException("Activity has been destroyed");
                }
                if (mPendingActions == null) {
                    mPendingActions = new ArrayList<>();
                }
                mPendingActions.add(action);
                scheduleCommit();
            }
        }
     
        private void scheduleCommit() {
            synchronized (this) {
                boolean postponeReady =
                        mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
                boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
                if (postponeReady || pendingReady) {
                    mHost.getHandler().removeCallbacks(mExecCommit);
                    mHost.getHandler().post(mExecCommit);
                }
            }
        }

    那么如果不把task1中构造的RequestManagerFragment放到pendingRequestManagerFragments中,那么在执行task2的时候也会再重新构造一个RequestManagerFragment,并且往主线程中放一个消息msg2,这个时候就会出现重复add的情况。

    所以在前面new 出来一个RequestManagerFragment,随后就把它放到pendingRequestManagerFragments中,那么task2再进来的时候从缓存中能取到,就不会再重新new和add了。

    那么下一个问题来了,为什么会出现下面这行代码,add后又需要马上发一个消息remove掉?在前面阻止掉task2重复new和add的操作后,就把这个缓存删掉,可以避免内存泄漏和内存压力:

    // RequestManagerRetriever.java
    pendingRequestManagerFragments.put(fm, current);
    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
    handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();

    四、Glide如何监听网络变化

    从上面页面生命周期的分析部分知道,对于任务的控制都是通过RequestManager,还是到它里面去看,实现网络变化监听的就是ConnectivityMonitor:

    // RequestManager.java
    public class RequestManager implements LifecycleListener,
        ModelTypes<RequestBuilder<Drawable>> {
      ...
      protected final Glide glide;
      protected final Context context;
      @Synthetic final Lifecycle lifecycle;
      private final RequestTracker requestTracker;
      private final RequestManagerTreeNode treeNode;
      private final TargetTracker targetTracker = new TargetTracker();
      private final Handler mainHandler = new Handler(Looper.getMainLooper());
      private final ConnectivityMonitor connectivityMonitor;
     
      ...
      RequestManager(
          Glide glide,
          Lifecycle lifecycle,
          RequestManagerTreeNode treeNode,
          RequestTracker requestTracker,
          ConnectivityMonitorFactory factory,
          Context context) {
        this.glide = glide;
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        this.context = context;
     
        connectivityMonitor =
            factory.build(
                context.getApplicationContext(),
                new RequestManagerConnectivityListener(requestTracker));
     
        if (Util.isOnBackgroundThread()) {
          mainHandler.post(addSelfToLifecycle);
        } else {
          lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
        ...
      }

    所以也是把它注册为ActivityFragmentLifecycle的观察者,ConnectivityMonitor通过ConnectivityMonitorFactory进行构造,提供了默认实现类DefaultConnectivityMonitorFactory:

    // DefaultConnectivityMonitorFactory.java
    public class DefaultConnectivityMonitorFactory implements ConnectivityMonitorFactory {
      private static final String TAG = "ConnectivityMonitor";
      private static final String NETWORK_PERMISSION = "android.permission.ACCESS_NETWORK_STATE";
     
      @NonNull
      @Override
      public ConnectivityMonitor build(
          @NonNull Context context,
          @NonNull ConnectivityMonitor.ConnectivityListener listener) {
        int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION);
        boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED;
        return hasPermission
            ? new DefaultConnectivityMonitor(context, listener) : new NullConnectivityMonitor();
      }
    }

    接着就往下看DefaultConnectivityMonitor, 在onStart中registerReceiver监听手机网络状态变化的广播,然后在connectivityReceiver中调用isConnect进行网络状态确认,根据网络状态是否变化,如果有变化就回调监听ConnectivityMonitor.ConnectivityListener:

    
    final class DefaultConnectivityMonitor implements ConnectivityMonitor {
      private static final String TAG = "ConnectivityMonitor";
      private final Context context;
      @SuppressWarnings("WeakerAccess") @Synthetic final ConnectivityListener listener;
     
      @SuppressWarnings("WeakerAccess") @Synthetic boolean isConnected;
      private boolean isRegistered;
     
      private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(@NonNull Context context, Intent intent) {
          boolean wasConnected = isConnected;
          isConnected = isConnected(context);
          if (wasConnected != isConnected) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
              Log.d(TAG, "connectivity changed, isConnected: " + isConnected);
            }
     
            listener.onConnectivityChanged(isConnected);
          }
        }
      };
     
      DefaultConnectivityMonitor(@NonNull Context context, @NonNull ConnectivityListener listener) {
        this.context = context.getApplicationContext();
        this.listener = listener;
      }
     
      private void register() {
        if (isRegistered) {
          return;
        }
     
        // Initialize isConnected.
        isConnected = isConnected(context);
        try {
          // See #1405
          context.registerReceiver(connectivityReceiver,
              new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
          isRegistered = true;
        } catch (SecurityException e) {
          // See #1417, registering the receiver can throw SecurityException.
          if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Failed to register", e);
          }
        }
      }
     
      private void unregister() {
        if (!isRegistered) {
          return;
        }
     
        context.unregisterReceiver(connectivityReceiver);
        isRegistered = false;
      }
     
      @SuppressWarnings("WeakerAccess")
      @Synthetic
      // Permissions are checked in the factory instead.
      @SuppressLint("MissingPermission")
      boolean isConnected(@NonNull Context context) {
        ConnectivityManager connectivityManager =
            Preconditions.checkNotNull(
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
        NetworkInfo networkInfo;
        try {
          networkInfo = connectivityManager.getActiveNetworkInfo();
        } catch (RuntimeException e) {
          if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e);
          }
          // Default to true;
          return true;
        }
        return networkInfo != null && networkInfo.isConnected();
      }
     
      @Override
      public void onStart() {
        register();
      }
     
      @Override
      public void onStop() {
        unregister();
      }
     
      @Override
      public void onDestroy() {
        // Do nothing.
      }
    }

    ConnectivityMonitor.ConnectivityListener是在RequestManager中传入,有网络重新连接后重启请求:

    // RequestManager.java
      private static class RequestManagerConnectivityListener implements ConnectivityMonitor
          .ConnectivityListener {
        private final RequestTracker requestTracker;
     
        RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
          this.requestTracker = requestTracker;
        }
     
        @Override
        public void onConnectivityChanged(boolean isConnected) {
          if (isConnected) {
            requestTracker.restartRequests();
          }
        }
      }

    五、Glide如何监测内存

    在Glide构造的时候会调用registerComponentCallbacks进行全局注册, 系统在内存紧张的时候回调onTrimMemory,然后根据系统内存紧张级别进行memoryCache/bitmapPool/arrayPool的回收:

    // Glide.java
      public static Glide get(@NonNull Context context) {
        if (glide == null) {
          synchronized (Glide.class) {
            if (glide == null) {
              checkAndInitializeGlide(context);
            }
          }
        }
     
        return glide;
      }
     
      private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
        Context applicationContext = context.getApplicationContext();
        ...
        applicationContext.registerComponentCallbacks(glide);
        Glide.glide = glide;
      }
     
      @Override
      public void onTrimMemory(int level) {
        trimMemory(level);
      }
     
      public void trimMemory(int level) {
        Util.assertMainThread();
        memoryCache.trimMemory(level);
        bitmapPool.trimMemory(level);
        arrayPool.trimMemory(level);
      }

    六、总结

    再回顾前面的四个问题,我相信聪明的你已经有了答案,文章的各小节标题就是根据问题来进行分析的,这么就不再赘述了,要不有凑字数的嫌疑。Glide的源码是比较庞大而且高质量的,所以一两篇文章是说不清楚的,后面对于Glide的源码分析还会有后续的文章,欢迎关注。

    更多内容敬请关注 vivo 互联网技术 微信公众号

    注:转载文章请先与微信号:labs2020 联系。

  • 相关阅读:
    Python代码项目目录规范v1.0
    博客自定义
    Linux之查看CPU信息
    Python字符界面函数库
    数组的遍历你都会用了,那Promise版本的呢
    NPM实用指北
    如何从0开发一个Atom组件
    使用JavaScript实现一个俄罗斯方块
    使用PostMan进行API自动化测试
    一个有味道的函数
  • 原文地址:https://www.cnblogs.com/vivotech/p/12018424.html
Copyright © 2020-2023  润新知