您的位置:首页 > 理论基础 > 计算机网络

Fresco内部诟病引起的初次从网络加载PNG图片失败

2018-02-08 19:45 211 查看
如题描述,这个问题在项目中存在已久,今天由于自己的功能在首页,初次启动的体验极其糟糕,所以硬下头皮把这个问题解决了。



先来描述一下怎么样一个差的体验吧。就是当我第一次加载网络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格式的图片,所以可能还是得需要上面两个方案里面的其中一个。如果你有更好的方案,请告诉我一下哈。开源万岁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐