Android开发经验谈Android开发Android开发

Android Glide4.0 源码遨游记(第一集)

2019-03-04  本文已影响8人  Android小Y
Glide

 

前言

Android中加载图片的形式有很多种,网上也有很多的知名图片加载库,例如Glide、Picasso、Fresco等等,它们为我们带来的方便就不需再多言了,无论是从加载到缓存还是占位图等等都提供了简易的Api,且实现强大的功能。本系列只针对Glide4.0版本源码进行分析,提高自身阅读源码的能力,同时也是为了了解其中加载的流程以及缓存的原理,本文尽可能地截图说明结合源码解析,如有疏忽之处,还请指教。

关于作者

一个在奋斗路上的Android小生,欢迎关注,互相交流
GitHubGitHub-ZJYWidget
CSDN博客IT_ZJYANG
简 书Android小Y


 

片头(Glide的基本使用)

1.首先肯定是添加依赖:

dependencies {
    compile 'com.github.bumptech.glide:glide:4.6.1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
}

2.流式调用,一行代码实现加载:

 //加载本地资源
Glide.with(context).load(R.drawable.ic_android).into(imageView);  
//加载网络图
Glide.with(context).load("http://....").into(imageView);   
//裁剪为圆形
Glide.with(context).load(R.drawable.ic_android).apply(RequestOptions.bitmapTransform(new CircleCrop())).into(imageView);  

调用几个api就能轻易实现我们想要的效果,更多用法详见 Glide使用文档

 

剧情(Glide.with 粮草先行)

由于3.0版本和4.0版本稍有差别,本文以4.0进行分析,Glide表面上简洁的调用,背后隐藏了很多的模块和复杂的逻辑,不然也没法做到这么强大的功能。可以看到,我们一般的使用是Glide.with(context).load(xxx).into(imageView);,那就从此处作为入口着手分析。

Glide.with()

首先看Glide的with方法,我这里是在Activity调用的,进去之后是这样的:

@NonNull
public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
}

可以看到这里,乍一看是获取一个RequestManager(RequestManager是请求相关的管理器,后文会提到,这里先略过),然后可以看到,Glide类中还有很多的重载方法:


看起来是为了适应不同的场景,但内部最终都是调用到getRetriever(Context context)方法,那我们再进入到getRetriever():
@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();
}

先是判断了传进来的context是否为空,然后调用了Glide.get(context).getRequestManagerRetriever(),先看Glide.get(context)

@NonNull
public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }

    return glide;
}

这里采用了设计模式中的单例模式的DCL写法,以保证整个应用中只有一个Glide实例,方便统一管理和调度。然后再调用getRequestManagerRetriever:

@NonNull
public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
}

返回了一个RequestManagerRetriever实例,那么RequestManagerRetriever是干嘛的呢?

/**
 * 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 {

  //忽略部分代码...

  @NonNull
  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(fragment.getActivity(),
          "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment);
    }
  }

  @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, null /*parentHint*/);
    }
  }

  @NonNull
  public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }

    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get(activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }

  @NonNull
  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  public RequestManager get(@NonNull 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, fragment);
    }
  }

  @NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }


  @NonNull
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
    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;
  }

  @NonNull
  private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
      @Nullable Fragment parentHint) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    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;
  }

  @NonNull
  RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

  /**
   * Used internally to create {@link RequestManager}s.
   */
  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);
    }
  };
}

这里源码有点长,先整体贴出来方便观看整体结构,嫌弃长的话可以先接着看,后面步骤会从代码里截图分步分析

里面同样重载了很多get方法,参数照样是Activity、Fragment、View、Context等多种类型(先留个疑问,为什么Glide要这么做呢?)首先看第一个get(Context context),可以看到里面对Context的类型做了判断。

RequestManagerRetriever#get(Context context)

如果是在子线程或者Application中调用的话,会调用getApplicationManager()来获取RequestManager
如果是主线程或者普通Context的话均会走各自的get方法,但其实它们本质最后只会调用到fragmentGet或者supportFragmentGet

getApplicationManager
其他普通Context获取的RequestManager
fragmentGet

然后再由它们将当前的Context的传递RequestManagerFactorybuild方法,new出了我们需要的RequestManager对象:

RequestManagerFactory

可以看到,两条线路的主要区别在于传进去的Lifecycle参数不一样,Application传进去的是ApplicationLifecycle,而Activity、Fragment等传进去的是getRequestManagerFragment()获得的Fragment对象的Lifecycle,那么getRequestManagerFragment获取的是什么Fragment呢?,可以看到获取的是Glide创建的一个隐藏的Fragment——RequestManagerFragment。RequestManagerFragment部分源码如下:

public class RequestManagerFragment extends Fragment {
    private final ActivityFragmentLifecycle lifecycle;
    public RequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
      }

    @VisibleForTesting
    @SuppressLint("ValidFragment")
    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();
    }
}

不难看出,只要这个Fragment的生命周期一变化,就会调用lifecycle的对应函数,那么ActivityFragmentLifecycle的对应函数又是干嘛的呢?

class ActivityFragmentLifecycle implements Lifecycle {
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());

  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);
  }

  @Override
  public void removeListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.remove(listener);
  }

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

  void onStop() {
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStop();
    }
  }

  void onDestroy() {
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onDestroy();
    }
  }
}

这里用到了观察者模式,即一旦它的onStart、onStop等函数被外界调用时,就会相应的遍历调用所持有的lifecycleListener对象的生命周期函数,结合上一步,也就是说:Fragment的生命周期一变化,就会调用到ActivityFragmentLifecycle类的生命周期函数,进而触发所有监听它的lifecycle监听器(可还记得刚才提到创建RequestManager的时候是传进去了我们的ActivityFragmentLifecycle,到时候RequestManager中会调用这里的addListener(this),那么RequestManager就相当于监听了ActivityFragmentLifecycle,就相当于我们平时写监听事件原理差不多)。

Glide正是利用这个隐藏的Fragment来监听所在页面的生命周期,从而控制我们的图片加载的生命周期(比如页面销毁了就停止加载图片),所以这也就是Glide要重载多个不同类型Context方法的原因,因为Application的Context是随着整个应用的生命周期变化而变化,Glide只要跟随着应用生命周期就可以了,但是如果只是具体页面那肯定有各自单独的生命周期,因此要区分各个场景来进行初始化。

RequestManagerRetriever分析完毕,其实它就是用来绑定当前生命周期并且返回我们所需要的RequestManager,还记得吗,刚才我们第一步获取RequestManager对象的时候,是调用的如下代码:

@NonNull
public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
}

getRetriever刚才也已经说了,是返回一个RequestManagerRetriever实例,那么这个时候调用的正是RequestManagerRetriever的get(Activity activity)方法,也就是说,Glide.with()方法会把我们当前所在的上下文Context传给Glide的RequestManagerRetriever生成对应的RequestManager对象。(此处以Activity为例, 会把我们的Activity实例传到RequestManagerRetriever中并且生成对应的RequestManager)

 

片尾

至此,Glide.with完成了它的使命。通过它绑定好了生命周期,并且拿到了接下来做请求要涉及到的RequestManager对象。
 

下集预告(Glide load 初露锋芒)

 


关注Android开发小栈,更多原创精选
上一篇下一篇

猜你喜欢

热点阅读