Android面试:一,常用库—Glide源码分析(基于最新版本 4.12.0-SNAPSHOT)

参考:

Glide4用法官方文档:https://muyangmin.github.io/glide-docs-cn/doc/getting-started.html

Glide3.7.0源码解析:https://blog.csdn.net/sinyu890807/column/info/15318

《Android面试题:Glide》 https://blog.csdn.net/songzi1228/article/details/84426165

Q:了解Glide的实现原理吗?

A:了解过,主要有几个方面:

  1. 图片缓存:内存缓存(LRU缓存+弱引用缓存),磁盘缓存,Bitmap对象池(Bitmap对象复用)
  2. 请求管理:根据生命周期取消request,重启失败request,请求优先级,缩略图请求管理
  3. 图片变换,图片解码

零,下载Glide源码

一,开始分析,Glide常用句式Glide.with(fragment).load(myUrl).into(imageView);

      先分析第一步Glide.with(context)

with方法是使用Glide加载图片的第一步,Glide类中的静态方法,返回RequestManager对象,根据传入的Context参数类型不同,主要有5个重载的with方法,区别是图片请求生命周期不同。

* @see #with(Context)
* @see #with(android.app.Activity)
* @see #with(android.app.Fragment)
* @see #with(androidx.fragment.app.Fragment)
* @see #with(androidx.fragment.app.FragmentActivity)

Glide可以根据当前页面的生命周期,自动重新开始或暂停或取消结束请求;实现原理就是根据传入的Context类型,在当前页面上生成一个看不见的fragment,来获得当前页面的生命周期的回调,进行请求相关的操作。如果传入的是Application,请求的生命周期将和应用一样长,不会自动取消;如果传入的是Activity或Fragment,当前Activity或Fragment退出时,请求将会自动终止。所以,从内存优化的角度看,应该传入当前页面的Context类型。比如child fragment页面上的Imagview显示图片,应该传入child fragment,而不是parent fragment和fragment所在的Activity。

可以看看源码的注释:

 /**
   * Begin a load with Glide by passing in a context.
   *
   * <p>Any requests started using a context will only have the application level options applied
   * and will not be started or stopped based on lifecycle events. In general, loads should be
   * started at the level the result will be used in. If the resource will be used in a view in a
   * child fragment, the load should be started with {@link #with(android.app.Fragment)}} using that
   * child fragment. Similarly, if the resource will be used in a view in the parent fragment, the
   * load should be started with {@link #with(android.app.Fragment)} using the parent fragment. In
   * the same vein, if the resource will be used in a view in an activity, the load should be
   * started with {@link #with(android.app.Activity)}}.
   *
   * <p>This method is appropriate for resources that will be used outside of the normal fragment or
   * activity lifecycle (For example in services, or for notification thumbnails).
   *
   * @param context Any context, will not be retained.
   * @return A RequestManager for the top level application that can be used to start a load.
   * @see #with(android.app.Activity)
   * @see #with(android.app.Fragment)
   * @see #with(androidx.fragment.app.Fragment)
   * @see #with(androidx.fragment.app.FragmentActivity)
   */
  @NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

所有with方法里面都是一句话,最终都是1.先调用getRetriever(context)方法获得RequestManagerRetriever对象,2.再调用RequestManagerRetriever对象的get(context)方法获得RequestManager对象。

RequestManagerRetriever这个类干嘛用的呢?源码里面的注释:A collection of static methods for creating new RequestManager or retrieving existing ones from activities and fragment.一些静态方法的集合,这些方法是用来创建新的requestManager对象或从activities和fragment中取回已存在的requestManager对象。

1.先看getRetriever(context)方法,

  @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();
  }

getRetriever(context)方法里面通过Glide.get(context)方法获取Glide单例对象,再调用getRequestManagerRetriever()简单的将requestManagerRetriever对象返回。在创建Glide单例对象的过程中,会创建并持有一个requestManagerRetriever对象。Glide单例对象在get方法里创建,这里先不跟进去看。(TODO:Glide的创建)

2.再看RequestManagerRetriever对象的get(context)方法,get方法和Glide里面的with方法一样有多个context子类参数的重载。

* @see #get(Context)
* @see #get(android.app.Activity)
* @see #get(android.app.Fragment)
* @see #get(androidx.fragment.app.Fragment)
* @see #get(androidx.fragment.app.FragmentActivity)

每个方法都看有点眼花,我们先看看其中的get(android.app.Activity)方法的实现,(TODO:重载的get方法)

/**
 * A collection of static methods for creating new {@link com.bumptech.glide.RequestManager}s or
 * retrieving existing ones from activities and fragment.
 */
public class RequestManagerRetriever implements Handler.Callback {
 
  ......
  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));
    }
  }
  ......
}

get(android.app.Activity)里面,先判断是否是后台线程,(如果是后台线程,请求无需根据activity页面的销毁而结束了),就直接调用参数ApplicationContext的get(Context)方法,创建一个和Application生命周期一样长的请求。如果是主线程,调用了fragmentGet方法并返回。

那么看看fragmenGet()方法:

  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;
  }

fragmenGet()方法里面,调用getRequestManagerFragment返回了一个fragment对象RequestManagerFragment,并创建一个RequestManager与fragment对象绑定,最后返回了RequestManager。

那么看看getRequestManagerFragment()方法:

  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;
  }

getRequestManagerFragment()方法里面,new RequestManagerFragment,并通过传入的FragmentManager添加到了页面上。从这里可以看出,RequestManagerFragment是根据页面的生命周期来管理Glide request请求的关键人物了。

那么看看RequestManagerFragment类里有什么,(可以源码的类的注释,一般都很清楚地描述了类的功能)

/**
 * A view-less {@link android.app.Fragment} used to safely store an {@link
 * com.bumptech.glide.RequestManager} that can be used to start, stop and manage Glide requests
 * started for targets the fragment or activity this fragment is a child of.
 *
 * @see com.bumptech.glide.manager.SupportRequestManagerFragment
 * @see com.bumptech.glide.manager.RequestManagerRetriever
 * @see com.bumptech.glide.RequestManager
 */
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public class RequestManagerFragment extends Fragment {

  ......
  private final ActivityFragmentLifecycle lifecycle;

  private RequestManager requestManager;

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

  RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }
 
  public void setRequestManager(@Nullable RequestManager requestManager) {
    this.requestManager = requestManager;
  }

  public RequestManager getRequestManager() {
    return requestManager;
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
      registerFragmentWithRoot(activity);
    } catch (IllegalStateException e) {
      // OnAttach can be called after the activity is destroyed, see #497.
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Unable to register fragment with root", e);
      }
    }
  }

  @Override
  public void onDetach() {
    super.onDetach();
    unregisterFragmentWithRoot();
  }

  @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();
  }

  private void registerFragmentWithRoot(@NonNull Activity activity) {
    unregisterFragmentWithRoot();
    rootRequestManagerFragment =
        Glide.get(activity).getRequestManagerRetriever().getRequestManagerFragment(activity);
    if (!equals(rootRequestManagerFragment)) {
      rootRequestManagerFragment.addChildRequestManagerFragment(this);
    }
  }

  private void unregisterFragmentWithRoot() {
    if (rootRequestManagerFragment != null) {
      rootRequestManagerFragment.removeChildRequestManagerFragment(this);
      rootRequestManagerFragment = null;
    }
  }
  ......
}

RequestManagerFragment类继承Fragemt类,在onAttach,onDetach方法中分别调用了registerFragmentWithRoot,unregisterFragmentWithRoot实现子fragment的添加和移除。RequestManagerFragment的构造方法中new ActivityFragmentLifecycle对象,并且在onStart,onStop,onDestroy中分别调用了ActivityFragmentLifecycle对象的onStart,onStop,onDestroy方法,看来就是通过ActivityFragmentLifecycle保存和通知页面的生命周期状态的变化。

那么看看ActivityFragmentLifecycle类,

/**
 * A {@link com.bumptech.glide.manager.Lifecycle} implementation for tracking and notifying
 * listeners of {@link android.app.Fragment} and {@link android.app.Activity} lifecycle events.
 */
class ActivityFragmentLifecycle implements Lifecycle {
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;

  /**
   * Adds the given listener to the list of listeners to be notified on each lifecycle event.
   *
   * <p>The latest lifecycle event will be called on the given listener synchronously in this
   * method. If the activity or fragment is stopped, {@link LifecycleListener#onStop()}} will be
   * called, and same for onStart and onDestroy.
   *
   * <p>Note - {@link com.bumptech.glide.manager.LifecycleListener}s that are added more than once
   * will have their lifecycle methods called more than once. It is the caller's responsibility to
   * avoid adding listeners multiple times.
   */
  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值