Android开源源码分析

512 阅读5分钟

glide源码分析

李保成

glide是 Bump出品的一个图片加载库

开源地址:https://github.com/bumptech/glide

glide使用方法如下:

Glide.with(this).load("http://pic9.nipic.com/20100919/5123760_093408576078_2.jpg")
.into(mImageview);

效果如下:


其总体架构如下:


with

先看一下with方法:

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

作用:初始化glide,返回一个RequestManger对象

以传入的是FragmentActivity为例:

getRetriever (activity)流程如下:


initializeGlide主要做了以下工作:

1. 获取应用中带注解的GlideModule(annotationGeneratedModule),这里要解释一下GlideModule:用户自定义glide配置模块,用来修改默认的glide配置信息。如果这个为空或者可配置menifest里面的标志为true,则获取menifest里面配置的GlideModule模块(manifestModules)。

2. 把manifestModules以及annotationGeneratedModule里面的配置信息放到builder里面(applyOptions)替换glide默认组件(registerComponents)

3. 各种初始化信息Glide glide = builder.build(applicationContext);

4. 看一下build的源码:

主要做了以下工作:

1)创建请求图片线程池sourceExecutor,创建硬盘缓存线程池diskCacheExecutor。动画线程池animationExecutor

2)依据设备的屏幕密度和尺寸设置各种pool的size

3)创建图片线程池LruBitmapPool,缓存所有被释放的bitmap, LruBitmapPool依赖默认的缓存策略和缓存配置。缓存策略在API大于19时,为SizeConfigStrategy,小于为AttributeStrategy。其中SizeConfigStrategy是以bitmap的size和config为key,value为bitmap的HashMap。

4)创建对象数组缓存池LruArrayPool,默认4M

5)创建LruResourceCache,内存缓存

6)注册管理任务执行对象的类(Registry),可以简单理解为:Registry是一个工厂,而其中所有注册的对象都是一个工厂员工,当任务分发时,根据当前任务的性质,分发给相应员工进行处理。

Glide build(@NonNull
Context context) {

  if
(sourceExecutor == null)
{

    sourceExecutor
= GlideExecutor.newSourceExecutor();

  }



  if
(diskCacheExecutor == null)
{

    diskCacheExecutor
= GlideExecutor.newDiskCacheExecutor();

  }



  if
(animationExecutor == null)
{

    animationExecutor
= GlideExecutor.newAnimationExecutor();

  }



  if
(memorySizeCalculator == null)
{

    memorySizeCalculator
= new MemorySizeCalculator.Builder(context).build();

  }



  if
(connectivityMonitorFactory
== null) {

    connectivityMonitorFactory
= new DefaultConnectivityMonitorFactory();

  }



  if
(bitmapPool == null)
{

    int
size = memorySizeCalculator.getBitmapPoolSize();

    if (size
> 0)
{

      bitmapPool
= new LruBitmapPool(size);

    }
else {

      bitmapPool
= new BitmapPoolAdapter();

    }

  }
  if
(arrayPool == null)
{
    arrayPool= new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());

  }
  if
(memoryCache == null)
{
    memoryCache= new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
  }
  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参数含义:

context上下文,engine:任务和资源管理(线程池,内存缓存和硬盘缓存对象

),memoryCache:内存缓存,bitmapPool:bitmap内存缓存,后续会单独介绍。

arrayPool: connectivityMonitorFactory:回调监听,defaultRequestOptions:默认请求配置,

defaultTransitionOptions:默认过度效果

getRetriever(activity).get(activity)

然后我们看一下get(activity)的流程:

public RequestManager get(@NonNull FragmentActivity activity) {

  if (Util.isOnBackgroundThread())
{

    return get(activity.getApplicationContext());

  } else {

    assertNotDestroyed(activity);

    FragmentManager fm =
activity.getSupportFragmentManager();

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

流程图如下:


主要工作是,创建一个supportFragment(SupportRequestManagerFragment),把Request和Fragment绑定在一起,主要是生命周期。

引用xiaodanchen.github.io/2016/08/19/…

文章中的一个图片:


总结以下with中的工作主要有以下几点:

1. 初始化配置信息(包括缓存,请求线程池,大小,图片格式等等)以及glide组件,

2. 将glide和Fragment的生命周期绑定在一块。

Load

asDrawable().load(string);

先分析一下asDrawable:


最后是创建了一个RequestBuilder对象

private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {

this.model = model;

isModelSet = true;

return this;

}

最终返回RequestBuider对象

into


private <Y extends Target<TranscodeType>> Y into(

    @NonNull Y target,

    @Nullable RequestListener<TranscodeType>
targetListener,

    @NonNull RequestOptions
options) {

  Util.assertMainThread();

  Preconditions.checkNotNull(target);

  if (!isModelSet) {

    throw new IllegalArgumentException("You
must call #load() before calling #into()");

  }



  options = options.autoClone();

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



  Request previous =
target.getRequest();

  if (request.isEquivalentTo(previous)

      &&
!isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {

    request.recycle();

    // If the request is
completed, beginning again will ensure the result is re-delivered,

    // triggering RequestListeners and
Targets. If the request is failed, beginning again will

    // restart the request, giving it
another chance to complete. If the request is already

    // running, we can let it continue
running without interruption.

    if (!Preconditions.checkNotNull(previous).isRunning())
{

      // Use the previous
request rather than the new one to allow for optimizations like skipping

      // setting placeholders, tracking
and un-tracking Targets, and obtaining View dimensions

     
// that are done in the individual Request.

      previous.begin();

    }

    return target;

  }



  requestManager.clear(target);

  target.setRequest(request);

  requestManager.track(target, request);



  return target;

}


构建Request对象,实际是在buildRequestRecursive里面创建了一个buildThumbnailRequestRecursive的对象以及errorRequestCoordinator(异常处理对象)


最后调用requestManager.track(target,
request);


track干了两件事:


void track(@NonNull Target<?> target, @NonNull Request
request) {

  targetTracker.track(target);

  requestTracker.runRequest(request);

}


1.     加入target目标队列(view)


2.     加入请求Request队列,如果缓存中没有开始请求数据


3. 
@Override

public void begin() {

  assertNotCallingCallbacks();

  stateVerifier.throwIfRecycled();

  startTime
= LogTime.getLogTime();

  if (model == null) {

    if
(Util.isValidDimensions(overrideWidth, overrideHeight)) {

      width
= overrideWidth;

      height
= overrideHeight;

    }

    //
Only log at more verbose log levels if the user has set a fallback drawable,
because

    // fallback Drawables indicate the
user expects null models occasionally.

    int
logLevel = getFallbackDrawable() == null ? Log.WARN
: Log.DEBUG;

    onLoadFailed(new GlideException("Received
null model"),
logLevel);

    return;

  }



  if
(status == Status.RUNNING) {

    throw
new IllegalArgumentException("Cannot restart a running request");

  }



  //
If we're restarted after we're complete (usually via something like a
notifyDataSetChanged

  // that starts an identical request
into the same Target or View), we can simply use the

  // resource and size we retrieved the
last time around and skip obtaining a new size, starting a

  // new load etc. This does mean that
users who want to restart a load because they expect that

  // the view size has changed will need
to explicitly clear the View or Target before starting

  // the new load.

  if
(status == Status.COMPLETE) {

    onResourceReady(resource, DataSource.MEMORY_CACHE);

    return;

  }



  //
Restarts for requests that are neither complete nor running can be treated as
new requests

  // and can run again from the
beginning.



  status
= Status.WAITING_FOR_SIZE;

  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {

    onSizeReady(overrideWidth, overrideHeight);

  }
else {

    target.getSize(this);

  }



  if
((status == Status.RUNNING || status ==
Status.WAITING_FOR_SIZE)

      &&
canNotifyStatusChanged()) {

    target.onLoadStarted(getPlaceholderDrawable());

  }

  if
(IS_VERBOSE_LOGGABLE) {

    logV("finished
run method in " + LogTime.getElapsedMillis(startTime));

  }

}

begin在onSizeReady执行engine.load, 先从弱引用中查找loadFromActiveResources(),如果有的话直接返回,没有再从内存中查找loadFromCache, 有的话会取出并放到ActiveResources里面,如果内存中没有,则创建engineJob(decodejob的回调类,管理下载过程以及状态)线程decodeJob,先下载,后解析,并把Job放到Hashmap里面。

流程图如下:


开启线程是从engineJob.start开始的

看一下DecodeJob线程的run方法,实际起作用的是runWrapped方法:

private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}

完整执行的情况下,会依次调用ResourceCacheGenerator、DataCacheGenerator和SourceGenerator中的startNext()

首次下载图片创建的是SourceGenerator:

runGenerators流程如下:

private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();

if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}

// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}

调用了SourceGenerator的startNext方法:

1、dataToCache数据不为空的话缓存到硬盘(非第一次)

2、 在modelLoaders里面找到ModelLoder对象(每个Generator对应一个ModelLoader)

3、通过(HttpGlideUrlLoader)buildLoadData获取到实际的loadData对象(key 为URL,value创建的HttpUrlFetcher对象)

4、通过loadData对象的fetcher对象(HttpUrlFetcher)的loadData方法来获取图片数据。

5、HttpUrlFetcher 通过HttpURLConnection网络请求数据

时序图如下:


至此,算是部分完整的分析了glide的过程,后续会继续完善。

参考:

blog.csdn.net/guolin_blog…

xiaodanchen.github.io/2016/08/22/…

blog.csdn.net/zsago/artic…

掘金的格式还不怎么会调整,看格式完整的可以去我的github

github.com/ouclbc/Anal…