一篇文章搞定《图片框架Glide》

前言

别走!别走!本篇文章一定不会因为Glide的庞大让你失去兴趣!!!
Glide的源码,非常非常的庞大,很多人都被直接的劝退。
如果你要一点点挖,解析全部的源码,那估计一个月你都解析不了这个框架的。
(说实话这个库的开源作者们也不是都了解框架中的各个分支的)
那么怎么办啊?

借用郭霖郭老师的一句话,抽丝剥茧、点到即止!!!!!!!
那么Glide我们怎么去搞呢?
首先大家要明白一点,看开源库是要学习什么呢?
答:(以下是我认为的学习三方框架的优先级)

  • 第一点:学习牛逼的主流程框架的搭建
  • 第二点:学习他优于常人的核心功能的实现
  • 第三点:学习他如何优雅的解决框架的问题
  • 第四点:学习他代码的设计模式,并帮他想一些能优化的点
  • 第五点:能将上面四个学习点,运用到你自己的项目中,解决一些棘手的问题

因此我们的主流程是一定要懂的,其次我们要对关键的一些问题进行剖析。

主流程

主流程:我是真没有必要去说。为什么呢?
答:因为我就是再说都没有下面这篇文章写的优美,真的会让人快速的理解。佩服佩服!!!
别给我点赞,给他点赞,好吧。
读本篇文章之前,兄弟们先把这篇文章读一遍吧,真的能让你很好理解主流程。
Glide源码难看懂?用这个角度让你事半功倍!

三大流程with、into、load捋顺

我们先从主线的角度上,把我们链式调用的三个函数搞定。

Glide.with(context).load(url).into(imageView);

With

首先是with函数,with函数给我们返回了RequestManager。
他负责初次创建实例化我们的Glide对象
并绑定我们的Glide的生命周期从而控制图片的加载暂停。

RequestManager requestManager = Glide.with(context)

我们Command点进去with看一下
Glide.java

public class Glide implements ComponentCallbacks2 {
    ...
    @NonNull
    public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
    }

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

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

    @NonNull
    public static RequestManager with(@NonNull Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
    }

    @SuppressWarnings("deprecation")
    @Deprecated
    @NonNull
    public static RequestManager with(@NonNull android.app.Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
    }

    @NonNull
    public static RequestManager with(@NonNull View view) {
        return getRetriever(view.getContext()).get(view);
    }
}

都是一些重载的with方法,可以通过参数看到他代表着传入不同组件的生命周期。
最终都是通过getRetriever去返回我们的RequestManager
那就往下看看getRetriever都做了什么

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    return Glide.get(context).getRequestManagerRetriever();
}
public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
}

这其实就是创建Glide并获取RequestManager
往下看一下他的创建过程

public static Glide get(@NonNull Context context) {
  if (glide == null) {
    GeneratedAppGlideModule annotationGeneratedModule =
        getAnnotationGeneratedGlideModules(context.getApplicationContext());
    synchronized (Glide.class) {
      if (glide == null) {
        checkAndInitializeGlide(context, annotationGeneratedModule);
      }
    }
  }
  return glide;
}

其中就是通过checkAndInitializeGlide去创建的,我们先不去看支线,只去看主线。看看他是怎么创建的

@GuardedBy("Glide.class")
private static void checkAndInitializeGlide(
    @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
   ....
  initializeGlide(context, generatedAppGlideModule);
}

@GuardedBy("Glide.class")
private static void initializeGlide(
    @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
  initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
}

@GuardedBy("Glide.class")
@SuppressWarnings("deprecation")
private static void initializeGlide(
    @NonNull Context context,
    @NonNull GlideBuilder builder,
    @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
    ......
    Context applicationContext = context.getApplicationContext();
    // 调用GlideBuilder.build方法创建Glide
    Glide glide = builder.build(applicationContext);
    // 注册内存管理的回调,因为Glide实现了ComponentCallbacks2接口
    applicationContext.registerComponentCallbacks(glide);
    // 保存glide实例到静态变量中
    Glide.glide = glide;
}   

可以看到Glide最终是通过Build一个工厂模式去创建的对象,当然创建对象使用工厂模式还是比较常见的。
看看Build中都默认配置了那些内容

@NonNull
  Glide build(@NonNull Context context) {
    // 创建请求图片线程池sourceExecutor
    if (sourceExecutor == null) {
      sourceExecutor =   GlideExecutor.newSourceExecutor();
    }

    // 创建硬盘缓存线程池diskCacheExecutor
    if (diskCacheExecutor == null) {
      diskCacheExecutor =   GlideExecutor.newDiskCacheExecutor();
    }

    // 创建动画线程池animationExecutor
    if (animationExecutor == null) {
      animationExecutor =   GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new   MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new   DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
      // 依据设备的屏幕密度和尺寸设置各种pool的size
      int size =   memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        // 创建图片线程池LruBitmapPool,缓存所有被释放的bitmap
        // 缓存策略在API大于19时,为SizeConfigStrategy,小于为AttributeStrategy。
        // 其中SizeConfigStrategy是以bitmap的size和config为key,value为bitmap的HashMap
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    // 创建对象数组缓存池LruArrayPool,默认4M
    if (arrayPool == null) {
      arrayPool = new   LruArrayPool(memorySizeCalculator.getArrayPoolSiz  eInBytes());
    }

    // 创建LruResourceCache,内存缓存
    if (memoryCache == null) {
      memoryCache = new   LruResourceCache(memorySizeCalculator.getMemoryCa  cheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new   InternalCacheDiskCacheFactory(context);
    }

    // 创建任务和资源管理引擎(线程池,内存缓存和硬盘缓存对象)
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(  ),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }

    RequestManagerRetriever requestManagerRetriever =
    new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
}

可以看到在Glide的工厂模式中我们配置了,图片、缓存、动画使用到的线程池,还有关键的任务引擎。
到此呢我们就只是将我们的上面Glide.with(context)中刚进来提及到的。
很多的重载方法中的getRetriever(context)说完了,他最终返回的是RequestManagerRetriever对象。之后调用了RequestManagerRetriever中的get(context)
我们来看看RequestManagerRetriever的get(context)中有什么

 @NonNull
    public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
    }
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  //判断是主线程还是子线程
  if (Util.isOnBackgroundThread()) {
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    FragmentManager fm = activity.getSupportFragmentManager();
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

Glide也就是通过这个get方法去绑定了他的生命周期的。(先记住是这里绑定的生命周期的。后面会着重讲)
可以看到会利用我们传入的Activity、Fragment、context去获取我们的RequestManager。从而利用生命周期对图片加载进行管理。
这里算是他的支线,先不说那么细,后面会把生命周期问题单独拿出来说的。也是方便有读者来专门看生命周期的问题的。

Load

其次就是我们的Load函数,load函数比较简单,让我们来看看。
他负责的很少,主要是初始化RequestBuilder,并设置需要加载的URL

RequestBuilder<Drawable> requestBuilder = Glide.with(context).load(URL)

可以看到他返回给我们的是RequestBuilder对象。
我们Command进去看看

public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }
public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}

load方法里面调用的asDrawable(),主要是初始化RequestBuilder

protected RequestBuilder(Glide glide, RequestManager requestManager,
      Class<TranscodeType> transcodeClass, Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    //注意,这里传入的是Drawable.classthis.transcodeClass = transcodeClass;
    this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.requestOptions = defaultRequestOptions;
    this.glideContext = glide.getGlideContext();
}

最后对model进行一个赋值,方便后面请求图片使用。并且更新他设置了URL的状态为true。

public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
}

就没了,可以看到load很简单就是创建了一个RequestBuilder。但是RequestBuilder却有着大用处,因为into是基于他调用的。into是很复杂的一个加载图片的过程,包含着三级缓存的知识。

Into

into非常的庞大,我们只去说他的主流程,并且只讲到网络请求的部分。因为在4.0版本之后,Glide已经使用OkHttp来解决网络请求图片了。
上面我们说到,Load帮我们返回一个RequestBuilder,来调用into函数。
让我们来具体看一看他的内容吧。

Glide.with(this).load("url").into(imageView)

RequestBuilder.into(ImageView imageView)

写了一部分还是放弃了,因为into流程实在是太庞大了。我希望这篇文章是关注一些重点的问题。和想让人们从当前框架的学习的内容,而不是花一个月的时间来研究一个into流程。(ps:真的需要一个月的时间能看明白就不错了)
推荐一个博客,大家如果想去深入的话可以去研读一下。这里就不搞在这里了。太臃肿了,而且容易让读者放弃。
Glide源码详细解析

其他常见问题详解

一定要把上面的主流程看一遍,咱们再来看下面的这些核心问题!!!
开整!!!

与其他图片框架有什么区别

首先主流的框架有Glide、Picasso、Coil
咱们只说关键点!!!真别墨迹别的乱七八糟的。
只说你如果选择框架,你去选择的理由!!!
Coil
先说Coil,Coil是Android上的一个全新的图片加载框架,它的全名叫做coroutine image loader,即协程图片加载库。
他有什么特点

  • 完全使用kotlin编写,使用了kotlin的协程,项目全是Kotlin的话,推荐这个图片框架。因为既然使用了Kotlin编写,那么一定适配了Kotlin的各种高阶、便捷的调用和使用。
  • 它支持GIF和SVG,并且可以执行四个默认转换:模糊,圆形裁剪,灰度和圆角。
  • 足够轻量,只有大概1500个核心方法。相比Glide和Picasso来说。
  • 因为是新库,所以对于之前Glide和Picasso的性能是有着提升的,内部使用了OKHttp、Okio、LifeCycle等开源库。

总结:如果你是kotlin工程、或者新起工程、就直接用Coil的。(ps:后面会出一篇文章去看Coil)
Glide
老牌框架Glide

  • 第一点肯定是要适配工程的,因为老牌框架,要看你工程中的使用情况。因为你不能想换新框架去改动整个项目啊。你想牵一发就动全身?
  • 三级缓存杠杠的,有效的避免OOM的出现,当然Coil也是杠杠的,相比之下Picasso再加载大图的时候就会出现性能的问题。
  • Glide可以加载Gif动图,Picasso不可以加载动图。
  • Glide它会为每种大小的ImageView都缓存一次。Picasso只缓存一个全尺寸的。因此Glide加载更快,但是需要内存空间更大。

总结:老项目中Glide使用很多无法重写、Gif图加载、空间换性能。就选Glide
Picasso
没他奶奶屌用,他的功能,咱们完全可以包装Glide去实现。

  • API使用简单,链式调用,一行代码就能使用,上手快
  • 持异步加载,避免在主线程上执行图片加载操作。
  • Picasso支持图片的转换功能,可以对图片进行常见的转换操作,如旋转、裁剪、缩放等。这样可以在不修改原始图片的情况下,对其进行各种处理,以满足不同的需求。

总结

  • 新项目推荐Coil。
  • 老项目Glide太多的话,还是去用Glide。
  • 因为包体积的优化,项目中要统一使用一个框架。

Glide怎么监听的生命周期

我们上面说到Glide.with(context)会为我们创建一个

RequestManager requestManager = Glide.with(activity)

首先会通过getRetriever获取RequestManagerRetriever。之后调用其中的get方法。

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

因为上面也已经讲解了getRetriever的相关内容,我们直接看get(activity)方法
主要分为子线程和主线程的两个场景。

  • 情况一:子线程的情况 如果是子线程就用Application级别的context,也就是不进行生命周期管理
  • 情况二:主线程的情况 利用一个空的Fragment进行生命周期管理
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  //判断是主线程还是子线程
  if (Util.isOnBackgroundThread()) {
    //情况一:子线程的情况 如果是子线程就用Application级别的context,也就是不进行生命周期管理 
    return get(activity.getApplicationContext());
  } else {
    //情况二:主线程的情况 利用一个空的Fragment进行生命周期管理
    // 判断Activity是否销毁
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    //获取FragmentManager
    FragmentManager fm = activity.getSupportFragmentManager();
    //创建RequestManager
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

情况一:子线程的情况
通过下面的源码可知,没有做生命周期的监听。
只是利用全局级别的context去创建RequestManager而已。(你可以认为就只是来取一个全局的Context)就去通过Glide.get去初始化Glide配置了。

return get(activity.getApplicationContext());

@NonNull
public RequestManager get(@NonNull Context context) {
  if (context == null) {
    throw new IllegalArgumentException("You cannot start a load on a null Context");
      //如果是在主线程并且不是Application的Context
  } else if (Util.isOnMainThread() && !(context instanceof Application)) {
    if (context instanceof FragmentActivity) {
    //通过FragmentActivity获取RequestManager
      return get((FragmentActivity) context);
    } else if (context instanceof Activity) {
    //通过Activity获取RequestManager
      return get((Activity) context);
    } else if (context instanceof ContextWrapper
        && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        //通过ContextWrapper获取RequestManager
      return get(((ContextWrapper) context).getBaseContext());
    }
  }
//通过全局的Content创建RequestManager
  return getApplicationManager(context);
}

@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
  if (applicationManager == null) {
    synchronized (this) {
      if (applicationManager == null) {
        //创建Glide 利用全局的Context
        Glide glide = Glide.get(context.getApplicationContext());
        applicationManager =
            factory.build(
                glide,
                new ApplicationLifecycle(),
                new EmptyRequestManagerTreeNode(),
                context.getApplicationContext());
      }
    }
  }

  return applicationManager;
}

情况二:主线程的情况 利用一个空的Fragment进行生命周期管理

 return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));

@NonNull
private RequestManager supportFragmentGet(
    @NonNull Context context,
    @NonNull FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {
  //利用创建的FragmentManager去获取SupportRequestManagerFragment(Fragment)
  SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
  RequestManager requestManager = current.getRequestManager();
  if (requestManager == null) {
    //初始化Glide配置
    Glide glide = Glide.get(context);
    //通过工厂方法创建requestManager,这个requestManager工厂方法可以在外部配置,
    //创建requestManager的时候就会注册相关Activity生命周期的回调
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    if (isParentVisible) {
      requestManager.onStart();
    }
    //设置RequestManager
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

来看看SupportRequestManagerFragment
它是一个绑定在Activity上不显示的Fragment用于监听Activity的状态
SupportRequestManagerFragment.java

 @NonNull
    private SupportRequestManagerFragment getSupportRequestManagerFragment(
        @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
        //通过tag找到Fragment
        SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
            //如果缓存了那么取出缓存的
            current = pendingSupportRequestManagerFragments.get(fm);
            if (current == null) {
                //没有缓存需要创建一个,创建ActivityFragmentLifecycle,监听生命周期
                current = new SupportRequestManagerFragment();
                //这是隐藏Fragment用于监听
                current.setParentFragmentHint(parentHint);
                if (isParentVisible) {
                    //调用生命周期onStart()
                    current.getGlideLifecycle().onStart();
                }
                pendingSupportRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                //删除FragmentManager
                handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }
}

这里是有小细节的,他缓存了当前的ActivityFragmentLifecycle,防止重复创建。没有才会创建的。能增加效率就增加效率。牛!!!
最后通过current.setParentFragmentHint(parentHint);
将我们创建好的设置给ActivityFragmentLifecycle。
我们往下看看current.setParentFragmentHint(parentHint);

void setParentFragmentHint(@Nullable Fragment parentFragmentHint) {
  this.parentFragmentHint = parentFragmentHint;
  if (parentFragmentHint == null || parentFragmentHint.getContext() == null) {
    return;
  }
  FragmentManager rootFragmentManager = getRootFragmentManager(parentFragmentHint);
  if (rootFragmentManager == null) {
    return;
  }
  //进行注册,通过parentFragmentHint获取的rootFragmentManager
  registerFragmentWithRoot(parentFragmentHint.getContext(), rootFragmentManager);
}

@Nullable
private static FragmentManager getRootFragmentManager(@NonNull Fragment fragment) {
  while (fragment.getParentFragment() != null) {
    fragment = fragment.getParentFragment();
  }
  return fragment.getFragmentManager();
}

可以看到这里获取了我们创建的空Fragment的FragmentManager。从而进行注册。
这里注册过程就结束了。那么他是怎么去监听生命周期的呢?
简化以下我们创建的空的Fragment(SupportRequestManagerFragment)的代码

public class SupportRequestManagerFragment extends Fragment {
    private final ActivityFragmentLifecycle lifecycle;

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

    @VisibleForTesting
    @SuppressLint("ValidFragment")
    public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    ActivityFragmentLifecycle getGlideLifecycle() {
        return lifecycle;
    }
    ......
}

可以看到我们利用这个注册过的Fragment的生命周期的感知,进行回调。这里的lifecycle可不是jetpack里面的Lifecycle哦。就是他自定义的回调事件。那么有回调事件就一定有注册、监听的地方。
这个注册监听的位置,是在我们利用工厂模式创建RequestManager去做的。
在我们的RequestManagerRetriever类中也就是我们源码中通过getRetriever(activity)时获取的。
之后通过get获取RequestManager。不知道大家还有没有印象了。
RequestManagerRetriever.java

        //创建Glide实例
        Glide glide = Glide.get(context);
        requestManager =factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);

        //factory接口
        public interface RequestManagerFactory {
            @NonNull
            RequestManager build(
            @NonNull Glide glide,
            @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode,
            @NonNull Context context);
        }

//默认的RequestManager工厂
        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);
                }
            };
public class RequestManager
implements ComponentCallbacks2, LifecycleListener,...{

    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;

        ......

        if (Util.isOnBackgroundThread()) {
            Util.postOnUiThread(addSelfToLifecycle);
        } else {
            //lifecycle的生命周期回调加入到RequestManager中
            lifecycle.addListener(this);
        }

        ......
    }

    public synchronized void onStart() {
        resumeRequests();
        // targetTracker维持着Traker列表,每个Traker属于Glide内部需要监听生命周期的逻辑
        targetTracker.onStart();
    }

    public synchronized void onStop() {
        pauseRequests();
        targetTracker.onStop();
    }
}

可以看到是在利用工厂模式构建RequestManager中对lifecycle 进行了注册,之后在空的Fragment中进行了触发。
最后的监听也在RequestManager中的onStart和onStop中了。最后也是通过实现了Request接口的SingleRequest进行了图片的暂停(clear)和开始(begin),两个方法。有兴趣的可以去看一下,就在SingleRequest.java中。

为什么Glide不能在子线程中with

因为在子线程调用,不会产生一个空白的Fragment和Activity进行生命周期的绑定;
可以看源码来证明这一点:(ps:认真看了上面的生命周期的,绝对知道怎么回事)

  • 情况一:子线程的情况 如果是子线程就用Application级别的context,也就是不进行生命周期管理
  • 情况二:主线程的情况 利用一个空的Fragment进行生命周期管理
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  //判断是主线程还是子线程
  if (Util.isOnBackgroundThread()) {
    //情况一:子线程的情况 如果是子线程就用Application级别的context,也就是不进行生命周期管理 
    return get(activity.getApplicationContext());
  } else {
    //情况二:主线程的情况 利用一个空的Fragment进行生命周期管理
    // 判断Activity是否销毁
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    //获取FragmentManager
    FragmentManager fm = activity.getSupportFragmentManager();
    //创建RequestManager
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

那这会怎么样呢?
因为没有了生命周期的监听,可能导致Activity销毁了,图片请求资源仍然存在,导致内存泄漏。
大家不要误解哦,这里的内存泄漏可不是说,图片或者引用的context,因为我们并没有引用当前的Activity和Fragment。那么这里的GCRoot是谁呢?
答:是子线程本身啊,兄弟们。 子线程本身就是GcRoot啊。(ps:之前说过活动线程是GcRoot的哦!!!)

如果在一个页面中使用Glide加载了一张图片,图片正在获取中,如果突然关闭页面,这个页面会造成内存泄漏吗?简单说一下内存泄漏的场景。

通过上面两个问题的分析,相比大家也知道答案了。
答案:

  • 因为Glide 在加载资源的时候,如果是在 Activity、Fragment 这一类有生命周期的组件上进行的话,会创建一个透明的 RequestManagerFragment 加入到FragmentManager 之中,感知生命周期,当 Activity、Fragment 等组件进入不可见,或者已经销毁的时候,Glide 会停止加载资源。因此也不会造成内存泄漏。
  • 但是在非生命周期的组件上进行时(Service、IntentService、BroadcastReceiver),会采用Application 的生命周期贯穿整个应用,所以 applicationManager 只有在应用程序关闭的时候终止加载。这样就会有内存泄漏的概率出现。

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

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加载了一个300x300的图片后,修改ImagerView尺寸为100x100那么是压缩再加载吗?

No,不是。Glide它会为每个不同尺寸的Imageview缓存一张图片,也就是说不管你的这张图片有没有加载过,只要imageview的尺寸不一样,那么Glide就会重新加载一次,这时候,它会在加载的imageview之前从网络上重新下载,然后再缓存。

也就是说:如果一个页面的imageview是300 * 300像素,而另一个页面中的imageview是100 * 100像素,这时候想要让两个imageview像是同一张图片,那么Glide需要下载两次图片,并且缓存两张图片。

源码证明这个答案:
可以看到width, height是组成EngineKey的成员,也就是说宽高不同,Key就不同,那么就不可能在之前的缓存HashMap中获取到缓存。
因此需要重新请求,缓存重新设置尺寸的图片。

public <R> LoadStatus load() {
    // 根据请求参数得到缓存的键
    EngineKey key = keyFactory.buildKey(model, signature, width, height,
     transformations,resourceClass, transcodeClass, options);
}

但是Picasso会不管imageview大小是什么,总是直接缓存整张图片。之后通过压缩等算法去调整。

怎么去设计一个图片框架呢

那就从后往前来吧!
1、网络请求:我直接上一个OkHttp
2、线程操作:异步加载+线程切换
3、编解码:支持多种格式图片的编解码
4、图片压缩:我直接抄一个鲁班压缩
5、多级缓存:我直接抄一个三级缓存
6、生命周期管理:通过对生命周期的管理,来管理我的图片框架的启动和停止
7、资源回收:Bitmap回收和复用(Bitmap.recycle)

总结

总结三方框架真的让人心力交瘁,但是很有意义(仅限于总结完的那一霎那)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值