Glide 系列五:InputStream 是怎么转成Bitmap 的?
本文概述:
- 上接系列四文章,分析了Glide 框架是怎么将字节流转成Bitmap 的;在文章末尾简单罗列了分析过程中的相关问题;
回退至HttpUrlFetcher.loadData()
-
从HttpUrlFetcher.loadDataWithRedirects () 回退至HttpUrlFetcher.loadData()
-
关键代码:
try { InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); //从这个地方就开始往回走了 callback.onDataReady(result); } -
从callback.onDataReady(result); 通过onDataReady 进入DataFetcher 接口
在DataFetcher 接口中,
-
由前文可知,我们是从SourceGenerator 过来的,因为走的是默认的缓存策略,所以应该这样回退
-
此时,进入SourceGenerator.onDataReadyInternal()
在SourceGenerator.onDataReadyInternal()
-
关键代码:
//继续向前回调,此时传入sourceKey,data 等参数 this.cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), this.originalKey); -
通过cb.onDataFetcherReady 回退至onDataFetcherGenerator 接口中的onDataFetcherReady 接口
在onDataFetcherReady 接口中
-
回退至DecodeJob.onDataFetcherReady()
-
进入decodeFromRetrievedData
-
进入decodeFromData
-
进入decodeFromFetcher
-
进入runLoadPath
- 关键代码:传入了图片宽高,选项(控件的scaleType),监听
return path.load( rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));- 注意,此时的数据仍未InputStream ,只是被不断封装了
-
通过path.load() 进入LoadPath 再进入loadWithExceptionList
在LoadPath.loadWithExceptionList ()
-
关键代码:
//此泛型会装载Bitmap Resource<Transcode> result = null; //通过decode 将InputStream 变成Bitmap result = path.decode(rewinder, width, height, options, decodeCallback); -
进入decode
-
进入decodeResource
-
进入decodeResourceWithList :传入图片宽高
-
关键代码
//这个result 就是最终拿到的Bitmap result = decoder.decode(data, width, height, options);
-
-
此时进入decode接口
-
进入其实现类:
-
凭什么说StreamBitmapDecoder 就是它的实现类?
- 在使用是,我们传入的URL 是String 字符串 ,最终我们需要去得到Bitmap,那么我们就要去解码Decode ,所以断定decode 接口的实现类应该选择StreamBitmapDecoder
在StreamBitmapDecoder.decode()
-
关键代码:这里就将InputStream 转成了Bitmap(看返回值)
-
继续向前回退,注意此时携带的参数是Bitmap ;
- 往后就只截取出重要流程
是怎么将Bitmap 加载出来的?
在EngineJob.notifyCallbacksOfResult
-
关键代码:将成功拿到的资源(Bitmap) 加入活动缓存
engineJobListener.onEngineJobComplete(this, localKey, localResource); //补充代码: public synchronized void onEngineJobComplete(xxx …… activeResources.activate(key, resource);- 第一次,从Http 服务器去拿;
- 第二次,从活动缓存中拿
在SingleRequest.onResourceReady ()
-
关键代码:设置图片加载位置(ImageViewTarget )
private final Target<R> target; //这个target 就是ImageViewTarget target.onResourceReady(result, animation); -
通过onResourceReady 进入 Target 接口中的onResourceReady 接口
- 选择实现类:ImageViewTarget
在ImageViewTarget.onResourceReady()
-
关键代码:设置资源
setResourceInternal(resource); -
此时进入ImageViewTarget.setResourceInternal()
-
关键代码:设置资源
setResource(resource); -
这个setResource 是一个抽象方法:
protected abstract void setResource(@Nullable Z resource);-
进入其实现类
-
-
在BitmapImageViewTarget.setResource
-
这里就将回调过程中携带的Bitmap 设置上了
@Override protected void setResource(Bitmap resource) { view.setImageBitmap(resource); }
问题汇总:
使用Glide时,with函数在子线程中,会有什么问题?
- 子线程,不会去添加 生命周期机制, 主线程才会添加 空白的Fragment 去监听 Activity Fragment 的变化。
- 子线程搞into 会报错的;
- 真的不建议,在子线程中用Glide ,很麻烦的;
使用Glide时,with函数传入Application后,Glide内部会怎么处理?
-
在MainActivity中,MainActivity销毁了,并会让Glide生命周期机制处理回收,只有在整个APP应用都没有的时候,跟随着销毁(上节课 ApplicationLIfecycle add onStart onDestroy 什么事情都没有做)。
-
跟子线程流程一样;这相当于跳过了缓存;
- 这个很不好,因为那个空白Fragment 是可以在内存紧张的时候,帮助释放资源,避免崩溃;
Glide 线程是怎么切换的?
- 需要展示的,就直接用Handler + MyLooper 去玩的;
Glide 会不会多次创建?
- Glide 是单例的;