Glide的源码分析<一>

来源:互联网 发布:java中文gbk编码转换 编辑:程序博客网 时间:2024/05/17 12:50

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>

//getApplicationManagerprivate 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;    }//getSupportRequestManagerFragmentSupportRequestManagerFragment 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  RequestTrackerpublic 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

原创粉丝点击