一. 问题
使用的Fresco版本为: 0.14.1
最近QA提了一个bug, 说项目中的一个图片选择页面的一张图片加载失败 (只有那一张图片失败, 其他的OK !). 瞬间蒙逼了......
经过各种调试, 发现那张图片的名称非常诡异, 是这样的EOX}6W$Q~5U$5O3U%~R94]P.jpg
. 我怀疑这张图片的命名有问题, 于是把名称改成a.jpg, 发现加载成功了!! 我加载图片的代码如下:
SimpleDraweeView draweeView;
//本地图片文件的路径, 如: `/storage/emulated/0/DCIM/Camera/EOX}6W$Q~5U$5O3U%~R94]P - 复制 (4).jpg`
String filepath;
//省略无关代码 ......
Uri uri = Uri.parse("file://" + filepath); //Uri.fromFile(new File(filepath));
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(draweeView.getWidth(), draweeView.getHeight()))
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(targetView.getController())
.setImageRequest(request)
.setCallerContext(uri)
.build();
draweeView.setController(controller);
URI中的特殊字符必须要经过转义, 否则会出问题. 更多讨论, 请看此issue
Uri.parse()
方法的定义如下:
/**
* Creates a Uri which parses the given encoded URI string.
*
* @param uriString an RFC 2396-compliant, encoded URI
* @throws NullPointerException if uriString is null
* @return Uri for this given uri string
*/
public static Uri parse(String uriString) {
return new StringUri(uriString);
}
从方法注释中可以看到, 此方法接收的参数是经过编码的uri字符串. 直接把文件的路径拼接一下传进去当然是不行的. 那么对文件路径拼接成的uri字符串进行编码, 然后传递给此方法不就可以了?! 然并卵!! 修改代码, 运行APP后发现所有图片都加载不出来了!! 上面的issue中有说到, 文件路径拼接成的uri字符串, 就算编码过再传给Uri.parse方法也是不行的 !!
issue中的说明如下(后面一个方法名说错啦, 是Uri.fromFile(File file)
, 而不是Uri.parseFromFile()
):
二. 解决方案
对于获取本地文件的uri对象, android.net.Uri类提供了一个静态方法: fromFile(File file)
. 其定义如下:
/**
* Creates a Uri from a file. The URI has the form
* "file://<absolute path>". Encodes path characters with the exception of
* '/'.
*
* <p>Example: "file:///tmp/android.txt"
*
* @throws NullPointerException if file is null
* @return a Uri for the given file
*/
public static Uri fromFile(File file) {
if (file == null) {
throw new NullPointerException("file");
}
PathPart path = PathPart.fromDecoded(file.getAbsolutePath());
return new HierarchicalUri(
"file", Part.EMPTY, path, Part.NULL, Part.NULL);
}
此方法接受一个文件对象, 然后返回此文件的Uri对象.
对于获取文件的Uri对象, 推荐使用此方法 !
最终解决方案: 使用android.net.Uri.fromFile(File file)方法获取本地文件的Uri对象.
代码如下:
Uri uri = Uri.fromFile(new File(filepath));
.
.
.
更多图片框架使用问题可以参考:
图片框架使用问题之一: UIL导致的OOM
图片框架使用问题之二: Fresco框架导致的OOM (com.facebook.imagepipeline.memory.BitmapPool.alloc(BitmapPool.java:4055))
References:
Fresco官方中文文档
Fresco: issue#1088, 加载本地文件之特殊文件名