Fresco内部诟病引起的初次从网络加载PNG图片失败
2018-02-08 19:45
211 查看
如题描述,这个问题在项目中存在已久,今天由于自己的功能在首页,初次启动的体验极其糟糕,所以硬下头皮把这个问题解决了。
先来描述一下怎么样一个差的体验吧。就是当我第一次加载网络PNG(当时并不知道是由于这个原因引起的)的时候,就一直显示的是默认的图片,本来按照Fresco的机制是,先显示默认图片,然后去网络加载图片,当图片下载下来就会替换掉原来的默认图片。
感谢https://github.com/facebook/fresco/issues/1803这篇文章让我有了思路。
其实在此之前我已经定位到错误了,我在加载图片的回调里面打了日志,发现没加载出来的图片都走了onFailure方法,抛出了一个异常
这个异常是在BitmapFactory.java里面抛出来的,有四个地方抛出,分别是不同的decodeResource,decodeByteArray,decodeStream,decodeFileDescriptor这几个方法抛出的,我们看看其中一个decodeStream吧
可以看到是在转换bitmap的时候抛出来的。
结合那篇文章可以得出结论是,Fresco在网络加载PNG的时候有一个BUG导致流解析为bitmap的时候抛出异常。
那就解决问题吧。这边我说一下我的解决思路。
第一种方案,就是链接里面说的修改Fresco的源码。可以翻到1.3.0版本的432行,我这里给你找出来了。
把下面这个if里面加上 &&encodedImage.getImageFormat() == DefaultImageFormats.PNG
由于现在已经是1.8.0版本的Fresco了,你可以找一下这个类定位到这个地方改。
第二种方案
用反射修改第一个方案里面的这个方法,这可以不修改Fresco的源码
第三种方案,我就是用这个方案的
由于我们App的图片是存在七牛的所以只要在你的Url的后面加上
把png通过七牛转成jpg,这样就完美解决了。
不过不可能整个app都是用jpg格式的图片,所以可能还是得需要上面两个方案里面的其中一个。如果你有更好的方案,请告诉我一下哈。开源万岁。
先来描述一下怎么样一个差的体验吧。就是当我第一次加载网络PNG(当时并不知道是由于这个原因引起的)的时候,就一直显示的是默认的图片,本来按照Fresco的机制是,先显示默认图片,然后去网络加载图片,当图片下载下来就会替换掉原来的默认图片。
感谢https://github.com/facebook/fresco/issues/1803这篇文章让我有了思路。
其实在此之前我已经定位到错误了,我在加载图片的回调里面打了日志,发现没加载出来的图片都走了onFailure方法,抛出了一个异常
IllegalArgumentException Problem decoding into existing bitmap
这个异常是在BitmapFactory.java里面抛出来的,有四个地方抛出,分别是不同的decodeResource,decodeByteArray,decodeStream,decodeFileDescriptor这几个方法抛出的,我们看看其中一个decodeStream吧
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) { // we don't throw in this case, thus allowing the caller to only check // the cache, and not force the image to be decoded. if (is == null) { return null; } Bitmap bm = null; Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap"); try { if (is instanceof AssetManager.AssetInputStream) { final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset(); bm = nativeDecodeAsset(asset, outPadding, opts); } else { bm = decodeStreamInternal(is, outPadding, opts); } if (bm == null && opts != null && opts.inBitmap != null) { throw new IllegalArgumentException("Problem decoding into existing bitmap"); } setDensityFromOptions(bm, opts); } finally { Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); } return bm; }
可以看到是在转换bitmap的时候抛出来的。
结合那篇文章可以得出结论是,Fresco在网络加载PNG的时候有一个BUG导致流解析为bitmap的时候抛出异常。
那就解决问题吧。这边我说一下我的解决思路。
第一种方案,就是链接里面说的修改Fresco的源码。可以翻到1.3.0版本的432行,我这里给你找出来了。
public class DecodeProducer implements Producer<CloseableReference<CloseableImage>> { //...... @Override protected synchronized boolean updateDecodeJob(EncodedImage encodedImage, boolean isLast) { boolean ret = super.updateDecodeJob(encodedImage, isLast); if (!isLast && EncodedImage.isValid(encodedImage) && encodedImage.getImageFormat() == DefaultImageFormats.JPEG) { if (!mProgressiveJpegParser.parseMoreData(encodedImage)) { return false; } int scanNum = mProgressiveJpegParser.getBestScanNumber(); if (scanNum <= mLastScheduledScanNumber) { // We have already decoded this scan, no need to do so again return false; } if (scanNum < mProgressiveJpegConfig.getNextScanNumberToDecode(mLastScheduledScanNumber) && !mProgressiveJpegParser.isEndMarkerRead()) { // We have not reached the minimum scan set by the configuration and there // are still more scans to be read (the end marker is not reached) return false; } mLastScheduledScanNumber = scanNum; } return ret; } //...... }
把下面这个if里面加上 &&encodedImage.getImageFormat() == DefaultImageFormats.PNG
if (scanNum < mProgressiveJpegConfig.getNextScanNumberToDecode(mLastScheduledScanNumber) && !mProgressiveJpegParser.isEndMarkerRead()) { // We have not reached the minimum scan set by the configuration and there // are still more scans to be read (the end marker is not reached) return false; }
由于现在已经是1.8.0版本的Fresco了,你可以找一下这个类定位到这个地方改。
第二种方案
用反射修改第一个方案里面的这个方法,这可以不修改Fresco的源码
第三种方案,我就是用这个方案的
由于我们App的图片是存在七牛的所以只要在你的Url的后面加上
"?imageView2/1/format/jpg"
把png通过七牛转成jpg,这样就完美解决了。
不过不可能整个app都是用jpg格式的图片,所以可能还是得需要上面两个方案里面的其中一个。如果你有更好的方案,请告诉我一下哈。开源万岁。
相关文章推荐
- Android图片框架对比Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较
- 图片加载用Fresco,网络请求用OKhttp+Retrofit实现
- Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较
- Picasso加载网络图片失败,提示decodestream时返回null
- 【iOS开发】SDWebImage框架,加载图片,失败之后,居然直接跳过不再去请求网络数据了?
- Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较
- img 加载网络图片失败 显示默认图片的方法
- android 开发 - 网络图片加载库 Fresco 的使用。
- ndroid 开发 - 网络图片加载库 Fresco 的使用。
- 网络加载图片对比(Fresco/Glide)
- Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较
- MVP实现用Retrofit请求网络数据Fresco加载图片,Recyclerview CheckBox显示并实现全选删除
- Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较
- Fresco加载网络图片的使用
- Android 图片控件Fresco加载网络图片
- 使用MVP+Retrofit+RxJava 图片加载使用Fresco 做网络请求并展示数据
- android 开发 - 网络图片加载库 Fresco 的使用。
- Retrofit+RxJava+Fresco图片加载框 请求网络数据
- android 开发 - 网络图片加载库 Fresco 的使用。
- fresco中设置占位/加载失败的图片 无效