记一次Fresco加载图片失败的分析

问题描述

最近在开发过程中,QA同学反馈了一个bug:在华为荣耀6(Android 4.4.2)上,有些页面的图片加载不出来,只能展示默认的占位图,效果如下所示:

在项目中,图片展示用的是FrescoSimpleDraweeView组件。第一次看到这个问题时,以为是Fresco的缓存出了问题,于是首先在手机的应用管理里,找到了对应的APP并清空了缓存。然而,重新启动APP后发现问题依然存在。于是深入分析了一下这个问题,发现了一个值得探讨的技术点,在此记录一下。

问题定位

在清空缓存不解决问题的情况下,接下来做了以下几方面的验证:

图片形状导致不兼容?

难道Fresco加载圆形图片有兼容性问题?于是又去检查了一下其他页面,发现有些普通的方形图片也显示不出来。

图片的URL有问题?

通过调试,拿到了图片的URL(注:为避免敏感信息,这里连接用的是自己测试的图片,效果都一样):oq54hiwcu.bkt.clouddn.com/2018-10-26-…。把整个图片链接放到浏览器中,发现可以正常打开图片。

如果拿另外一个可以加载成功的图片的URL,通过SimpleDraweeViewsetImageURI(String uriString)方法,设置给这个显示异常的组件,发现可以正常加载出来!

认真对比了一下两个链接,发现加载失败的链接中除了有中文外,没有其他的差别。把上面图片链接中大发两个字做URLEncode之后,得到的链接是:oq54hiwcu.bkt.clouddn.com/2018-10-26-…。当把经过URLEncode之后的图片链接重新设置给SimpleDraweeView的时候,发现图片可以正常显示了!

于是问题初步定位:带特殊字符的URL(如中文,空格等),在这款手机上加载不出来!

虽然问题定位到了,但是为什么同样的URL在其他手机(手头有Android 8.0等高版本手机)上可以正常加载图片,在这款手机上就无法加载成功呢?难道Fresco存在兼容性问题?

问题原因

在项目中,图片的URL是通过调用SimpleDraweeViewsetImageURI(String uriString)方法进行设置的。要解决弄明白上面的问题,就需要深入追踪了一下这里源码的实现。

众所周知,Fresco设计是三级缓存:内存、文件、网络。针对我们当前遇到的问题,初步推断应该是图片在通过网络加载的时候出问题的。

如果在Fresco初始化时没有自定义网络加载引擎,那Fresco默认使用的是系统自带的HttpURLConnection。通过阅读源码可知,Fresco中通过网络加载图片,最终是通过HttpUrlConnectionNetworkFetcher类中的downloadFrom(Uri uri, int maxRedirects)方法来完成网络请求的。源码简化如下:

// HttpUrlConnectionNetworkFetcher.java

private HttpURLConnection downloadFrom(Uri uri, int maxRedirects) throws IOException {
	HttpURLConnection connection = openConnectionTo(uri);
	connection.setConnectTimeout(mHttpConnectionTimeout);
	int responseCode = connection.getResponseCode();
	...
}
复制代码

从上面的代码中可以看出,Fresco默认使用HttpUrlConnection做网络请求。经过调试发现,带特殊字符的URL在connection.getResponseCode()执行时,每次返回的responseCode都是403,即服务器不响应此次请求。当链接中的特殊字符经过URLEncode之后,responseCode正常返回200。也就是说这个版本的HttpURLConnection在底层并不会自动对URL的Params中的特殊字符做URLEncode

解决方案

至此,问题的原因已经清晰明了了,解决方案可以有两种方案:

统一URLEncode

对于项目中所有的图片URL,在调用SimpleDraweeViewsetImageURI(String uriString)前,统一对参数做一次URLEncode即可。

需要注意的是:对链接做URLEncode不能像下面这样直接把整个链接作为参数传入,因为这样会把一些并不需要转换的特殊字符也直接转换掉。

String query = java.net.URLEncoder.encode("pg=q&kl=XX&stype=stext");

// query: pg%3Dq%26kl%3DXX%26stype%3Dstext
复制代码

比如:当我们要对pg=q&kl=XX&stype=stext的链接做URLEncode时,如果采用上述方法,最终得到的结果是:pg%3Dq%26kl%3DXX%26stype%3Dstext,这并不符合我们的预期。因为我们只希望把Params的部分做URLEncode。这就需要对URL的Params解析

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值