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
- Glide的源码分析<一>
- Glide源码分析 一
- Glide源码分析(一)——DiskLruCache磁盘缓存的实现
- glide源码分析
- Glide 源码分析
- Glide源码分析
- Glide源码分析
- Glide源码阅读一
- Glide源码分析1 - 框架
- Glide源码分析-生命周期管理
- Glide源码分析-下载图片
- android开发-Glide源码分析
- 深入Glide图片加载库的Demo源码分析
- 源码分析glide对线程中断的优化
- 深入理解Glide源码,分析之路(二):Glide的执行流程,史上最详细、易懂
- Glide原理分析(一)
- 深入理解Glide源码,分析之路(一):基本用法,史上最详细、易懂
- Glide源码分析3 -- 绑定Activity生命周期
- JS我来了哈哈哈哈
- nodejs学习1:Express的API分析与试验
- Monkey测试5——补充
- form标签下的type属性的属性值演示
- Git和Github简单教程
- Glide的源码分析<一>
- Tensorflow(2) Graph
- UE4 Sequencer的事件调用
- @RequestMapping的produces属性
- Android
- 五大联赛积分榜查询工具
- C++ UpdateData()
- AngularJs 完美解决模板缓存 $templateCache
- ubuntu通过apt-get安装JDK8