图片框架使用问题之三: Fresco框架加载本地图片失败(文件名包含特殊字符)


图片框架使用问题之三: Fresco框架加载本地图片失败(文件名包含特殊字符)_第1张图片
20150330130402_0.gif

一. 问题

使用的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()):

图片框架使用问题之三: Fresco框架加载本地图片失败(文件名包含特殊字符)_第2张图片
F01BB8B9-E80B-41A5-A3AF-9BA8243C30ED.png

二. 解决方案

对于获取本地文件的uri对象, android.net.Uri类提供了一个静态方法: fromFile(File file). 其定义如下:

/**
 * Creates a Uri from a file. The URI has the form
 * "file://". Encodes path characters with the exception of
 * '/'.
 *
 * 

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, 加载本地文件之特殊文件名

你可能感兴趣的:(图片框架使用问题之三: Fresco框架加载本地图片失败(文件名包含特殊字符))