Glide的源码分析

1,034 阅读6分钟

Glide的源码分析

glide作为android的图片加载框架,实现起来比较简便:

Glide.with(mActivity)
                .load(newsBean.getNimg())-----load url to get image
                .error(R.drawable.icon_scord)
                .centerCrop()
                .placeholder(R.drawable.icon_scord)
                .into(viewHolder.ivIcon);

glide对图片的处理各方面个人认为还是不错的:
(1)支持Memory和Disk图片缓存。
(2)支持gif和webp格式图片。
(3)根据Activity/Fragment生命周期自动管理请求。
(4)使用Bitmap Pool可以使Bitmap复用。
*(5)对于回收的Bitmap会主动调用recycle,减小系统回收压力。
包括其内部机制:

这里写图片描述

1.

ok~进入正题 开始源码分析;先看requestManager的获取–Glide.with

    public static RequestManager with(FragmentActivity activity) {
            RequestManagerRetriever retriever =
             RequestManagerRetriever.get();
        return retriever.get(activity);
    }

.with方法可以传入context/activty/fragment来获取requestManager,用法比较灵活;接下来继续看源码—->RequestManagerRetriever.get<即RequestManagerRetriever>

//getApplicationManager
private RequestManager getApplicationManager(Context context) {
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {

                    applicationManager = new RequestManager
                    (context.getApplicationContext(),
                     new ApplicationLifecycle(), 
                     new EmptyRequestManagerTreeNode());
                }
            }
        }

        return applicationManager;
    }

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

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

//supportFragmentGet
    RequestManager supportFragmentGet(Context context, FragmentManager fm) {
        SupportRequestManagerFragment current=
        getSupportRequestManagerFragment(fm);
        RequestManager requestManager = 
        current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager
            (context, current.getLifecycle(), current.
            getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

//getSupportRequestManagerFragment
SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
        SupportRequestManagerFragment current 
        = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
            current = pendingSupportRequestManagerFragments.get(fm);
            if (current == null) {
                current = new SupportRequestManagerFragment();
                pendingSupportRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }

在RequestManagerRetriever类中提供两个不同参的get方法,分别是get(context)/get(xxxActivity),获取fragment事务fm,同context一起传入supportFragmentGet()中;至于为什么还需要一个RequestManagerRetriever并有各种重载方法,主要是因为Glide通过SupportRequestManagerFragment和RequestManager关联了Activity或Fragment的生命周期,用来做pauseRequests等操作。

2.

接着来看Glide中.load(url)的放方法,

public RequestBuilder<Drawable> load(@Nullable Object model) {
 return asDrawable().load(model);
}

public RequestBuilder<Drawable> asDrawable() {
     return as(Drawable.class).
     transition(new DrawableTransitionOptions());
}

public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
     return new RequestBuilder<>(glide.getGlideContext(), 
     this, resourceClass);
}

看的出来load即是实现asDrawable().load(model);在load中加载的方法中最终返回RequestBuilder,在我看来可以理解为一个网络的构造器;大部分设置在RequestOptions里,这就是下面这一句:

apply(RequestOptions.placeholderOf(R.drawable.loading))

RequestOptions可以设置各种请求图片的相关选项;注意在这可以设置默认图片,加载失败的图片,包括各种加载策略等;RequestOptions继承自BaseRequestOptions,但全是工厂方法生成各种RequestOptions;<以后详解在这不做解释,只需要记得这可以设置一堆附加的属性等>

3.

然后看加载的发起点into方法。 //com.bumptech.glide.DrawableRequestBuilder:

//into(ImageView view)
 @Override
    public Target<GlideDrawable> into(ImageView view) {
        return super.into(view);
    }

//com.bumptech.glide.GenericRequestBuilder:

//into(ImageView view)
public Target<TranscodeType> into(ImageView view) {
        Util.assertMainThread();
        if (view == null) {
            throw new IllegalArgumentException("You must pass in a non null View");
        }

        if (!isTransformationSet && view.getScaleType() != null) {
            switch (view.getScaleType()) {
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                //$CASES-OMITTED$
                default:
                    // Do nothing.
            }
        }

        return into(glide.buildImageViewTarget(view, transcodeClass));
    }

//into(Y target)
    public <Y extends Target<TranscodeType>> Y into(Y target) {
        Util.assertMainThread();
        if (target == null) {
            throw new IllegalArgumentException("You must pass in a non null Target");
        }
        if (!isModelSet) {
            throw new IllegalArgumentException("You must first set a model (try #load())");
        }

        Request previous = target.getRequest();

        if (previous != null) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }

        Request request = buildRequest(target);
        target.setRequest(request);
        lifecycle.addListener(target);
        requestTracker.runRequest(request);

        return target;
    }

Target是要加载到的目标<一般是holder中的ivIcon等字段>,参数为imageView,内部生成了一个DrawableImageViewTarget。这里最主要的操作是buildRequest然后交给RequestManager去track。—–>接下来看track的方法:

void track(Target<?> target, Request request) {
 targetTracker.track(target);
 requestTracker.runRequest(request);
}

// class  RequestTracker
public void runRequest(Request request) {
 requests.add(request);
 if (!isPaused) {
   request.begin();
 } else {
   pendingRequests.add(request);
 }
}

TargetTrack中记录了所有正在加载的图片,通过方法requestTracker.runRequest(request);来判断加载过程的生命周期,如果!isPaused,这里相当于activity中onPause,如果!isPaused,则调用request.begin();开始加载,反之则进入队列即pendingRequests.add(request);进行加载等待… 除了设置缩略图的情景,使用的Request都是SingleRequest,看一下它的begin方法:

public void begin() {
 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;
 }

 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 (Log.isLoggable(TAG, Log.VERBOSE)) {
   logV("finished run method in " + LogTime.getElapsedMillis(startTime));
 }
}

看上面的代码,首先判断tarGet的大小,大小已知则调用 onSizeReady(overrideWidth, overrideHeight);进行下一步逻辑,如果不知道tartget大小则通过target.getSize(this);来获取tartget的大小,然后继续调用onSizeReady();onSizeReady()就是调用一下方法<通过一下方法实现逻辑>

public <R> LoadStatus load(
   GlideContext glideContext,
   Object model,
   Key signature,
   int width,
   int height,
   Class<?> resourceClass,
   Class<R> transcodeClass,
   Priority priority,
   DiskCacheStrategy diskCacheStrategy,
   Map<Class<?>, Transformation<?>> transformations,
   boolean isTransformationRequired,
   Options options,
   boolean isMemoryCacheable,
   boolean useUnlimitedSourceExecutorPool,
   ResourceCallback cb) {
 Util.assertMainThread();
 long startTime = LogTime.getLogTime();

 EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
     resourceClass, transcodeClass, options);

 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
 if (cached != null) {
   cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
   if (Log.isLoggable(TAG, Log.VERBOSE)) {
     logWithTimeAndKey("Loaded resource from cache", startTime, key);
   }
   return null;
 }

 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
 if (active != null) {
   cb.onResourceReady(active, DataSource.MEMORY_CACHE);
   if (Log.isLoggable(TAG, Log.VERBOSE)) {
     logWithTimeAndKey("Loaded resource from active resources", startTime, key);
   }
   return null;
 }

 EngineJob<?> current = jobs.get(key);
 if (current != null) {
   current.addCallback(cb);
   if (Log.isLoggable(TAG, Log.VERBOSE)) {
     logWithTimeAndKey("Added to existing load", startTime, key);
   }
   return new LoadStatus(cb, current);
 }

 EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
     useUnlimitedSourceExecutorPool);
 DecodeJob<R> decodeJob = decodeJobFactory.build(
     glideContext,
     model,
     key,
     signature,
     width,
     height,
     resourceClass,
     transcodeClass,
     priority,
     diskCacheStrategy,
     transformations,
     isTransformationRequired,
     options,
     engineJob);
 jobs.put(key, engineJob);
 engineJob.addCallback(cb);
 engineJob.start(decodeJob);

 if (Log.isLoggable(TAG, Log.VERBOSE)) {
   logWithTimeAndKey("Started new load", startTime, key);
 }
 return new LoadStatus(cb, engineJob);
}

在Engine.load中,先loadFromCache,如果缓存没有命中就再loadFromActiveResources,这是两级内存缓存,第一级是LruCache,第二级是ActiveCache,主要作用是,有可能一个图片很早就被加载了,可能已经从LruCache被移除掉了,但这个图片可能还在被某一个地方引用着,也就是还是Active的,那它就可能在将来仍被引用到,所以就把它保留在二级的ActiveCache中,ActiveCache中是以弱引用引用图片的,并通过ReferenceQueue监测弱引用的回收,然后用Handler.IdleHandler在CPU空闲时被被回收的引用项从ActiveCache中移除。

接下来看对应的Key是否已经正在加载,如果是的话,就addCallback,这样如果有多个地方同时请求同一张图片的话,只会生成一个加载任务,并都能收到回调,这点是比Universal-Image-Loader好的地方。

正常的加载流程是生成一个EngineJob和一个DecodeJob,通过engineJob.start(decodeJob)来进行实际的加载。

public void start(DecodeJob<R> decodeJob) {
 this.decodeJob = decodeJob;
 GlideExecutor executor = decodeJob.willDecodeFromCache()
     ? diskCacheExecutor
     : getActiveSourceExecutor();
 executor.execute(decodeJob);
}

EngineJob.start直接将DecodeJob交给Executor去执行了(DecodeJob实现了Runnable接口)。DecodeJob的加载操作放到了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);
 }
}

private DataFetcherGenerator getNextGenerator() {
 switch (stage) {
   case RESOURCE_CACHE:
     return new ResourceCacheGenerator(decodeHelper, this);
   case DATA_CACHE:
     return new DataCacheGenerator(decodeHelper, this);
   case SOURCE:
     return new SourceGenerator(decodeHelper, this);
   case FINISHED:
     return null;
   default:
     throw new IllegalStateException("Unrecognized stage: " + stage);
 }
}

private Stage getNextStage(Stage current) {
 switch (current) {
   case INITIALIZE:
     return diskCacheStrategy.decodeCachedResource()
         ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
   case RESOURCE_CACHE:
     return diskCacheStrategy.decodeCachedData()
         ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
   case DATA_CACHE:
     return Stage.SOURCE;
   case SOURCE:
   case FINISHED:
     return Stage.FINISHED;
   default:
     throw new IllegalArgumentException("Unrecognized stage: " + current);
 }
}

以上三步即为gide.with(xxx).load(xxx).into(xxx)的源码,了解源码的你相信会更加熟练的使用Glide