Android-图片加载框架Glide主线分析

深入主流框架源码,有利于思维拓展,以及遇到问题能究其根本,所以今天就来扒一扒Glide的基本主线。

Glide框架之所有受欢迎,一是因为它的加载支持生命周期管理,二是支持gif加载,三是占用内存小(默认配置图片编码格式为rgb565),内部使用了多级缓存。但是目前也发现有缺点,实际应用中发现对于gif的支持不是特别好,有时候帧数会出一些问题。

惯例,先说依赖配置:implementation'com.github.bumptech.glide:glide:4.7.1'

以下是基本使用代码,先看看Glide.with()方法都干了些啥

activiy

@NonNull

public static RequestManager with(@NonNull FragmentActivity activity) {

return getRetriever(activity).get(activity);

}

@NonNull

private static RequestManagerRetriever getRetriever(@Nullable Context context) {

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 get(context).getRequestManagerRetriever();

}

@NonNull

public static Glide get(@NonNull Context context) {

if (glide ==null) {

Class var1 = Glide.class;

        synchronized(Glide.class) {

if (glide ==null) {

checkAndInitializeGlide(context);

            }

}

}

return glide;

}

private static void checkAndInitializeGlide(@NonNull Context context) {

if (isInitializing) {

throw new IllegalStateException("You cannot call Glide.get() in registerComponents(), use the provided Glide instance instead");

    }else {

isInitializing =true;

        initializeGlide(context);

        isInitializing =false;

    }

}

private static void initializeGlide(@NonNull Context context) {

initializeGlide(context, new GlideBuilder());

}

private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {

//以上非关键代码注释

Glide glide = builder.build(applicationContext);

    //以下非关键代码注释

    Glide.glide = glide;

}

从以上调用链可以看出,with方法在Glide的initializeGlide中,创建了Glide类中的静态单例对象glide,然后with方法里面第一个函数getRetriever(activity)返回的是一个RequestManagerRetriever,这个是啥,暂时先不管,解析来看调用的第二个函数,RequestManagerRetriever的get方法。这里会调用supportFragmentGet方法,

@NonNull

public RequestManager get(@NonNull FragmentActivity activity) {

if (Util.isOnBackgroundThread()) {

return this.get(activity.getApplicationContext());

    }else {

assertNotDestroyed(activity);

        androidx.fragment.app.FragmentManager fm = activity.getSupportFragmentManager();

        return this.supportFragmentGet(activity, fm, (Fragment)null, isActivityVisible(activity));

    }

}

@NonNull

private RequestManager supportFragmentGet(@NonNull Context context, @NonNull androidx.fragment.app.FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {

SupportRequestManagerFragment current =this.getSupportRequestManagerFragment(fm, parentHint, isParentVisible);

    RequestManager requestManager = current.getRequestManager();

    if (requestManager ==null) {

Glide glide = Glide.get(context);

        requestManager =this.factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);

        current.setRequestManager(requestManager);

    }

return requestManager;

}

从RequestManagerRetriever#supportFragmentGet这个方法以及函数内部调用的第一个方法getSupportRequestManagerFragment可以看出,这里创建了一个SupportRequestManagerFragment,并且添加到了activity,并且在这里绑定了一个RequestManager,这2个玩意,其实就是Glide能根据生命周期管理请求的关键东东,后面会说。

到这里先总结一下,Glide.with做了几件事情:

1. 实例化了Glide对象

2.创建了一个名为SupportRequestManagerFragment的无UI的Fragment,与我们的activity进行关联,并且为SupportRequestManagerFragment设置了一个名为RequestManager的对象

--------------------------------------------------------------------------------------------

接下来再看load方法,load方法构建了一个RequestBuilder,暂时先不看,我们先看下一个方法,也就是into(设置到某个Imageview)上,看源码

@NonNull

public ViewTargetinto(@NonNull ImageView view) {

//上面是一些请求配置项,暂不看

return into(

glideContext.buildImageViewTarget(view, transcodeClass),

      /*targetListener=*/ null,

      requestOptions);

}

private >Y into(

@NonNull Y target,

    @Nullable RequestListener targetListener,

    @NonNull RequestOptions options) {

//省略。。。

//这里buildRequest构建了一个Request对象,深入追踪会发现,实际创建的是一个叫做SingleRequest的对象,由于代码调用比较深,这里就不一一贴出来了

  Request request = buildRequest(target, targetListener, options);

 //省略。。。

//这里是关键方法,这里调用了RequestManager的track方法,内部调用了RequestTracker的runRequest方法传进去的就是刚才构建的Request(实际是SingleRequest)

  requestManager.track(target, request);

  return target;

}

下面我们看下RequestTracker类的runRequest干了些啥。。。

public void runRequest(@NonNull Request request) {

requests.add(request);

  if (!isPaused) {

request.begin();

  }else {

if (Log.isLoggable(TAG, Log.VERBOSE)) {

Log.v(TAG, "Paused, delaying request");

    }

pendingRequests.add(request);

  }

}


RequestTracker这个类,看到里面管理了2个集合,一个是requests,一个是pendingRequests,有没有感觉似曾相识的感觉,没错,okhttp内部也有自己维护的队列(运行中队列,待执行队列),不过这里是的维护方式是有区别的,我们后面说。这里runRequest方法,把singleRequet添加到了requests集合中,判断如果isPaused,则调用Request的begin方法,否则添加到pendingRequests中,这里isPaused猜测应该是跟页面生命周期相关的字段,看下isPause的字段都在哪些地方有赋值,{pauseRequests,pauseAllRequests,resumeRequests},看下这些方法都是在哪些地方有调用


RequestManager

发现没有,又回到了RequestManager的这个类来了,刚才我们说到了,Glide创建的无UI的SupportRequestManagerFragment,里面也塞了一个RequestManger,这里是不是可以认为Glide的生命周期维护是有Activity传递给SupportRequestManagerFragment,SupportRequestManagerFragment再传递给RequestManager呢?看一下RequestManager的继承实现关系,实现了LifecycleListener接口,然后在SupportRequestManagerFragment这个Fragment类中寻找相关线索,发现创建的时候有个ActivityFragmentLifecycle这个玩意,这个玩意在SupportRequestManagerFragment的onStart/onStop/onDestory中都有调用,但是这个东西跟我们的RequestManager有什么关系呢?我们最终不是调用的是它吗,继续查看ActivityFragmentLifecycle,发现它有个addListener方法,看下它的调用地方,发现了什么,原来在RequestManager构建的时候就把它自己丢给了ActivityFragmentLifecycle,是不是现在一瞬间就清晰了。Activity的生命周期变化传递给了SupportRequestManagerFragment,SupportRequestManagerFragment将变化传递给了ActivityFragmentLifecycle,ActivityFragmentLifecycle将变化最终给到了RequestManager,然后RequestManager最终调用到了RequestTracker的resumeRequests/pauseRequests。


ActivityFragmentLifecycle


RequestManager

刚才上面提到过Glide的RequestTracker里面维护的2个集合跟Okhttp中Dispatcher所处理的方式不一样,Okhttp是任务执行完后会执行finish方法,判断运行中队列个数以及待执行队列的情况,进行任务转移,而Glide是在页面onStop的时候直接就把所有的请求都给停止了,然后在onStart的时候,把那些没有完成或者失败的请求再次开始请求。

上面只提到了Glide的调用链,基本思路,以及生命周期的管理如何实现,但是最终的请求,我们还没有追踪到,就是SingleRequest的begin方法,这个方法后面的逻辑涉及到后面的多级缓存以及相求相关,这里简单梳理一下

SignleRequest#begin()->SignleRequest#onSizeReady(overrideWidth, overrideHeight);     -> engine.load(***)这个方法里面涉及到缓存读取(loadFromActiveResources/loadFromCache),由于时间关系,凌晨一点多了,后面逻辑有时间再补充,白天上班撸码,晚上还要回来学习复习巩固知识,时间有点不够用

你可能感兴趣的:(Android-图片加载框架Glide主线分析)