【面试技巧】当面试官问你glide的时候,是想问什么?glide生命周期如何实现?

2020-11-02 10:26:06 浏览数 (1)

去面试的时候,我们也经常被问到这样的问题:项目用什么图片加载框架?为什么选择这个框架?glide是现在主流的图片加载框架,被问到的概率非常高。面试官这样问,最想听到的是什么答案?Lru算法原理还是三层缓存的理解?以我的理解,Lru和三层缓存是很基本的,一般的图片加载框架都用到,这应该不是面试官真正的目的。面试官最想问的应该是glide最大的优点是什么?并且能够针对源码讲出是怎么实现的。本篇文章将围绕这两个问题去讨论。

说在前面的话

glide的源码对于我来说,很复杂。一开始觉得云里雾里,后来看了很多遍才理顺。写这篇文章是抓住主线去讲述,很多的细节没有讲到,而且是按照我自己认为更好理解的顺序去看源码。看过源码却还是很晕的朋友们可以看下我的思路,也许有用。如果没有看过源码的,可以去看其它大神写的关于glide的系列文章,会更好。整篇文章只针对glide的with()传入Activity环境变量作讲解。

glide最大的优点

glide最大的优势就是对bitmap的管理是跟随生命周期去发生改变的。其它的框架基本都是用Lru算法,当Activity销毁的时候,是不会释放之前加载图片占用的所有内存。glide的优势就是当Activity销毁的时候,之前加载的所有图片的内存都释放了。glide是如何做得这一点的,这是我们需要去深挖的地方。

glide如何监听到Activity的生命周期

在看glide相关资料的时候,知道一个结论,glide是通过新建一个空的Fragment去监听Activity的生命周期。带着这个结论然后按调用的步骤看源码,结果被绕晕了,各种调用和类,看了很多次还是很混乱。后来我换个思路,如果简化的来说,就是新建的Fragment和当前的Activity关联上,glide根据Fragment的生命周期去做操作,onStart()``发起请求或者重新请求、onStop()暂停请求、``onDestory()`取消清除请求。所以我先找出新建的Fragment,然后顺着思路,去查看它在哪里和Actvity关联上。

首先找到Fragment,也就是RequestManagerFragment,内部创建的无UI的Fargment。它在RequestManagerRetriever类的getRequestManagerFragment()被调用。相关源码:

代码语言:javascript复制
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);//获取Fragment
    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);//保存到map集合
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();//添加到Actvity中
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

这部分代码涉及FragmentManager的使用,忘了怎么使用的朋友可以去复习一下。代码不难理解,就是一个目的,得到Fragment并且返回这个Fragment。先通过findFragmentByTag获取,如果为null,则会从pendingRequestManagerFragments这个Map集合去获取,如果还是为null,则直接new 一个Fragment,并且保存到pendingRequestManagerFragments以及添加到Activity中。这部分的代码就是Fragment和Actvity关联上了,这样就可以通过Fragment得知当前Activty的生命周期。追踪RequestManagerFragment,看看它的生命周期里面做了什么操作,源码如下:

代码语言:javascript复制
private final ActivityFragmentLifecycle 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();
  }

Fragment的的生命周期里(我们只关注贴出代码的三个生命周期),ActivityFragmentLifecycle类都调用了相同名字的方法,接下来看看ActivityFragmentLifecycle的相应方法里面有什么操作。

代码语言:javascript复制
private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
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();
    }
  }

相应的方法里都调用了LifecycleListener的相关方法,LifecycleListener是一个接口,作用在源码里写得很清楚:An interface for listener to lifecycle events.,监听生命周期的接口。既然是个接口,就找出实现它的类,实现LifecycleListener的类是RequestManager。RequestManager类,它实现了LifecycleListener接口,三个方法里面的内容如下。

代码语言:javascript复制
/**
   * 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 synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

  /**
   * Lifecycle callback that unregisters for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
   */
  @Override
  public synchronized void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }

  /**
   * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
   * all completed requests.
   */
  @Override
  public synchronized 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);
  }

requestTracker是用来追踪取消和重新启动正在进行,已完成和失败的请求。看到这里我们可以猜想,RequestManagerFragment生命周期变化的时候回调RequestManager的onStart、onStop、onDestroy方法,然后Request就做出相应的操作,Activity的生命周期是和Request的生命周期绑定起来。要验证这个猜想,就要找到RequestManager是怎么样监听到Fragment的生命周期的。我们来看看RequestManager的创建

代码语言:javascript复制
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);//将Fragment的lifecycle交给RequestManager管理
    }
    return requestManager;
  }

以上代码说明,通过工厂模式创建RequestManager,并且将Fragment的lifecycle交给RequestManager管理,代码current.getGlideLifecycle()就是获取到lifecycle。再回头去看ReqeustManager,找到了lifecycle操作LifecycleListener的代码,在构造器将LifecycleListener添加到lifecycle,源码如下:

代码语言:javascript复制
 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);

   //省略部分代码
  }

Lifecycle是用来添加和删除LifecycleListener,而ReqeustManager的构造方法里,将LifecycleListener添加到lifecycle里面。

看到这里,也就验证了我们的猜想了。ReqeustManager是来代理管理Request的生命周期方法,也就是请求的生命周期。glide就是通过ReqeustManager监听到Fragment的生命周期,从而根据生命周期管理让Request做出相对应的请求。

我们在使用glide的时候很简单,就是Glide.with(this).load(url).into(imageView); glide的with方法返回的也是ReqeustManager类,这个过程中按顺序看下来,涉及两个关键方法,fragmentGet()getRequestManagerFragment(),相关的源码已经在以上讲解中贴出。 下面我将把获取到ReqeustManager这个过程中涉及的一些重要的方法和类做一些说明,只是我的个人理解,如有不对,欢迎指正。

fragmentGet()

1、调用getRequestManagerFragment()得到RequestManagerFragment,也就是Fragment的管理类。 从RequestManagerFragment拿到RequestManager和ActivityFragmentLifecycle 2、RequestManager如果不为空直接返回,如果为空则通过工厂创建一个RequestManager,并且将ActivityFragmentLifecycle传入。

getRequestManagerFragment()

1、得到RequestManagerFragment,也就是Fragment 2、将Fragment加入到Activity

RequestManagerFragment

1、Fragment的管理类,继承Fragment 2、在构造方法里创建ActivityFragmentLifecycle类 3、在Fragment的onStart()、onStop()、onDestroy()里调用ActivityFragmentLifecycle类里相应的方法。

ActivityFragmentLifecycle

1、实现Lifecycle接口 2、在Lifecycle的addListener(@NonNull LifecycleListener listener);里,将listener一一添加进LifecycleListener的集合,并且调用LifecycleListener相应的方法做一些操作,最终的目的是让每个RequestManager对应一个LifecycleListener

RequestManager

1、实现LifecycleListener接口 2、将RequestManager自身添加到lifecycle方法中,也就是ActivityFragmentLifecycle中,这样就可以监听到Fragment的生命周期。

glide还有很多很多的知识点,本篇文章只是介绍glide是如何关联上Activity的生命周期的,当我们在面试时候,能把实现的过程讲出来,我想这是会加分的。看懂源码,也就能在 面试过程中针对不同的问题去解答。

最后

要想面试成功进大厂,面试前的准备肯定是要很充分的。

e自己的知识准备得怎么样,这直接决定了你能否顺利通过一面和二面,所以在面试前来一个知识梳理,看需不需要提升自己的知识储备是很有必要的。

关于知识梳理,这里再分享一下我面试这段时间的复习路线:(以下体系的复习资料是我从各路大佬收集整理好的)

知识梳理完之后,就需要进行查漏补缺,所以针对这些知识点,我手头上也准备了不少的电子书和笔记,这些笔记将各个知识点进行了完美的总结:

最后我在这里分享一下这段时间从朋友,大佬那里收集到的一些2019-2020BAT 面试真题解析,里面内容很多也很系统,包含了很多内容:Android 基础、Java 基础、Android 源码相关分析、常见的一些原理性问题等等,可以很好地帮助我们深刻理解Android相关知识点的原理以及面试相关知识

这份资料把大厂面试中常被问到的技术点整理成了 PDF ,包知识脉络 诸多细节;还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

以上内容均放在了开源项目:github 中已收录,里面包含不同方向的自学Android路线、面试题集合/面经、及系列技术文章等,资源持续更新中...

最后祝大家面试顺利,早日找到自己心仪的公司。

0 人点赞