第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

Glide源碼全解析GlideAPP和.with()方法背后的故事

標(biāo)簽:
Android

前言

在上一篇文章中我们体验了Glide-4.0的强大,以及更加简便的API,很多童鞋已经开始迁移了,那么接下来我们一起探索一下他的神奇之处:

首先我们来看一下4.0的基本用法:

GlideApp.with(this)        .load(R.raw.large_giphy_logo)        .into(giphyLogoView);

就这么简简单单的一句代码,其实Glide在背后帮我们做了成吨的事情。所以为了解开大家的好奇,一起来解析一下Glide-4.0源码。

准备

想要阅读源码那么久需要先下载源码, 
GitHub地址: 
https://github.com/bumptech/glide 
我们这一篇是基于4.1.0讲解的,后续如果想查看这个版本的代码可以通过下面的链接: 
https://github.com/bumptech/glide/tree/v4.1.1 
剩下的应该不用说了吧,直接 
git clone https://github.com/bumptech/glide.git

下载好源码之后我们可以看到里面有五个demo,我们可以运行一下看看效果,这里就不给大家挨着展示了。 

5b77a8ad000167c706000540.jpg

到这里我们即将开启我们的源码之旅。 
可能我们最大的疑惑就是glide为什么就用了简单的一句代码就可以实现图片的加载。 
GlideApp.with(this).load(R.raw.large_giphy_logo).into(giphyLogoView);

首先,先说一下今天的解读思路: 
Glide基本的加载步骤是三步那么我们就分别解读这三步with()load()into()到底是如何实现的,以及GlideApp是什么鬼? 
今天这篇文章先讲述一下 GlideApp和 with()背后的故事。

GlideApp如何诞生?

1、 @GlideModule注解做了什么事情?

/**
 *在编译时,为AppGlideModules和LibraryGlideModules提供注入。
 *
 *替换掉  AndroidManifest.xml 中value="GlideModule" 的 <meta-data /> 。
 *这里需要注意后续需要用到<meta-data />这个标签,先记住此处
 */@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)public @interface GlideModule {
  /**
   *此处返回的name就是你在使用时的class name。
   *
   *eg:将GlideApp改为GlideAppX
   *那么通过注解生成的类就是GlideAppX
   *那么你使用时候就会是 GlideAppX.with(this)
   */
  String glideName() default "GlideApp";
}

注视已经详细介绍了这个类的作用,后面我们来看一下生成的GlideApp。

2、GlideApp能做啥?

GlideApp这个类事通过上面的注解获得到的,是不容许被修改的,是Glide在应用中的入口,做一些初始化,获取图片存储路径之类的,非常简单,注释也非常清楚,就不详细叙述了。 
 此处省略中间代码,

public final class GlideApp {
  private GlideApp() {
  }  /**
   * @see Glide#getPhotoCacheDir(Context)
   */
  @Nullable
  public static File getPhotoCacheDir(Context context) {    return Glide.getPhotoCacheDir(context);
  }

  ...
  ... 省略
  ...  /**
   * @see Glide#with(View)
   */
  public static GlideRequests with(View view) {    return (GlideRequests) Glide.with(view);
  }
}

那么到了这里我们已经知道了GlideAPP是如何诞生的以及GlideApp都有哪些方法。

接下来我们就详细看一下AppGlideModule做什么了,为啥要继承AppGlideModule?

3.为什么继承AppGlideModule?

我们先来看一下AppGlideModule的API 
Class AppGlideModule

5b77a8ae0001620706000377.jpg

(1)isManifestParsingEnabled

我们先来看一下isManifestParsingEnabled() 
用途:是否检测AndroidManifest里面的GlideModule 
该方法,默认返回true。 
但是如果我们通过上面的注解和继承AppGlideModule生成自己的module时,官方要求我们实现这个方法,返回并且false,这样避免AndroidManifest加载两次。

下面是注释原文:

Implementations should return false after they and their dependencies have migrated to Glide's annotation processor.

我之前的文章对这个方法也有讲解可以去了解一下:

(2)applyOptions

在Glide被创建之前,对GlideBuilder进行设置。 
方案非常多就不详细叙述了,如下图所示: 

5b77a8b0000163fd04000287.jpg

:这个方法只调用一次。

开始阅读—with()背后的故事!

1.GlideApp.with()方法干啥了?

  /**
   * @see Glide#with(Context)
   */
  public static GlideRequests with(Context context) {    return (GlideRequests) Glide.with(context);
  }  ...
  ... 入参不同省略  ...

  /**
   * @see Glide#with(View)
   */
  public static GlideRequests with(View view) {    return (GlideRequests) Glide.with(view);
  }

从上面的代码中可以看到我们使用GlideApp.with()其实还是在使用Glide.with()方法。 
那么我们这里直接研究Glide.with()方法:

2.Glide.with()方法究竟做啥了?

with()方法是Glide中的一组静态方法,有好几个重载方法,如下所示:

public static RequestManager with(Context context) {   return getRetriever(context).get(context);
 } public static RequestManager with(Activity activity) {   return getRetriever(activity).get(activity);
 } public static RequestManager with(FragmentActivity activity) {   return getRetriever(activity).get(activity);
 } public static RequestManager with(android.app.Fragment fragment) {   return getRetriever(fragment.getActivity()).get(fragment);
 } public static RequestManager with(Fragment fragment) {   return getRetriever(fragment.getActivity()).get(fragment);
 } public static RequestManager with(View view) {   return getRetriever(view.getContext()).get(view);
 }

可以看到,with()方法的重载种类非常多,如下:

with(android.app.Activity) 
with(android.app.Fragment) 
with(android.support.v4.app.Fragment) 
with(android.support.v4.app.FragmentActivity) 
with(android.view)

每一个with()方法重载的代码都非常简单,都是调用调用getRetriever(activity).get(activity),返回一个RequestManager对象。

那么我们先来看一下getRetriever(...).get(...)做了什么事情?

3.getRetriever(…).get(…)做了什么事情?

1、getRetriever(…)做了什么事情?

如下图,这里是一个静态方法,返回RequestManagerRetriever, 

5b77a8b2000163d721700444.jpg

这里官方已经帮我们做了判空处理,注释非常详细,这里就不再介绍了。 
这里我们获得了RequestManagerRetriever,接下来看些.get(...)方法做了什么?

2、getRetriever(…).get(…)做了什么事情?

第一步我们获得了RequestManagerRetriever,那么接下来我们详细看一下里面的get()方法。

RequestManagerRetriever是一个用静态方法的集合,这些方法包括新建RequestManager或者从Activity/Fragment检索出现有的。 
API:RequestManagerRetriever 
5b77a8b50001e71411920658.jpg源代码如下:

public class RequestManagerRetriever implements Handler.Callback {
  public RequestManager get(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);
    }    public RequestManager get(FragmentActivity activity) {      if (Util.isOnBackgroundThread()) {        return get(activity.getApplicationContext());
      } else {
        assertNotDestroyed(activity);
        FragmentManager fm = activity.getSupportFragmentManager();        return supportFragmentGet(activity, fm, null /*parentHint*/);
      }
    }    public RequestManager get(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);
      }
    }    public RequestManager get(Activity activity) {      if (Util.isOnBackgroundThread()) {        return get(activity.getApplicationContext());
      } else {
        assertNotDestroyed(activity);
        android.app.FragmentManager fm = activity.getFragmentManager();        return fragmentGet(activity, fm, null /*parentHint*/);
      }
    }    public RequestManager get(View view) {      if (Util.isOnBackgroundThread()) {        return get(view.getContext().getApplicationContext());
      }

      Preconditions.checkNotNull(view);
      Preconditions.checkNotNull(view.getContext(),          "Unable to obtain a request manager for a view without a Context");
      Activity activity = findActivity(view.getContext());      // The view might be somewhere else, like a service.
      if (activity == null) {        return get(view.getContext().getApplicationContext());
      }      // Support Fragments.
      if (activity instanceof FragmentActivity) {
        Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);        if (fragment == null) {          return get(activity);
        }        return get(fragment);
      }      // Standard Fragments.
      android.app.Fragment fragment = findFragment(view, activity);      if (fragment == null) {        return get(activity);
      }      return get(fragment);
    } 
}

这里我们挨着对上面代码进行解析:在这里我们将入参分为两类,一类是Application, 
一类是非Application

(1)当传入Application时: 
如果在Glide.with()方法中传入的是一个Application对象,那么这里就会调用上面的get()方法重载,最后来获取一个RequestManager对象。其实这是最简单的一种情况,因为Application对象的生命周期即应用程序的生命周期,因此Glide并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。

public RequestManager get(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);
  }

对ContextWrapper不熟悉的童鞋,可以参考这篇文章 Android源码装饰模式—ContextWrapper

(2)当传入的是非Application时: 

5b77a8b60001cb0b07750489.jpg

:上图中可以看出来,如果在子线程,默认当application处理!!!

通过上图我们会发现不论传入Activity、FragmentActivity、Fragment最终都会调用图中红框中的方法,而这两个方法最终流程都是一致的就是那就是会向当前的Activity当中添加一个隐藏的Fragment。 
下面是两个方法的具体代码: 对应的app包和v4包下的两种Fragment的情况。

接下来我们看fragmentGet()supportFragmentGet()两个方法。

fragmentGet()方法

private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
      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());
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

supportFragmentGet()方法

  private RequestManager supportFragmentGet(Context context, FragmentManager fm,
      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());
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

为什么使用Glide需要support-v4包??

:注意啦! 
答:应该有童鞋遇到过下面的问题,引入Glide需要导入v4包,他在思考自己没有用到啊,其实是glide这里用到了,需要引入com.android.support:support-v4

是不是发现看了源码之后明白了为啥要添加v4包了!!!~~~~

那么这里为什么要添加一个隐藏的Fragment呢?

:注意啦! 
答:因为Glide需要知道加载的生命周期。很简单的一个道理,如果你在某个Activity上正在加载着一张图片,结果图片还没加载出来,这时候Activity被用户关掉了,那么图片就应该取消加载,可是Glide并不知道Activity的生命周期,怎么办呢? 
于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。 
RxPermissions也用到了这种技巧。

既然有了Application,为什么不用registerActivityLifecycleCallbacks而是用隐藏的Fragment?

:注意啦! 
答:registerActivityLifecycleCallbacks是可以实现,并且我的小伙伴在自己的某些工程中也在使用,但是个人理解是这样的: 

registerActivityLifecycleCallbacks监控所有的Activity生命周期,然而当你使用Glide加载图片时,并不是所有的Activity都会用到Glide加载图片(大多数情况),所以呢,使用registerActivityLifecycleCallbacks存在资源浪费的现象。不仅如此,你监控了所有的activity怎么和Glide想要监控的Activity关联到一块去,虽然可以实现,但是这个办法真心不实用,既然Glide给了我们这么完美的解决方案我们就要学以致用,以后尽力用到自己的工程中去。

原文链接:http://www.apkbus.com/blog-866962-77533.html

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消