最近在整合融云IM的SDK,过程曲折,由于人家也是刚起步就不过多吐槽了,不过有个问题涉及到的一系列学习要记录一下。
问题
融云1.2sdk的发送图片消息把图片分成两个部分,一部分是缩略图,跟着走消息通道一起发给接收方;一部分是原图,上传到7牛云平台。
这个时候接收方得到的图片信息原图为一个网络路径,缩略图为一个uri。
由于在聊天页面的时候肯定要显示缩略图,所以问了下融云的开发人员这个uri怎么用,给的解释是这已经是接收方本地的一个路径,可以调用他们的一个api直接转成drawable。
重点是我这边的聊天消息有做本地持久化,所以怎么存这个uri就是问题所在。
解决过程
方案有几个
1.把uri存到本地,然后取的时候再次通过融云提供的api转成drawable。
2.直接用原图的路径去七牛取缩略图。
3.把转出来的drawable持久化掉。
首先如果我是融云方的人的话肯定直接用七牛的缩略图功能,因为他可以通过对图片地址加参数来缩放、剪裁图片,而且速度相当不错,
可是融云既然不知道基于什么原因,在发消息的时候非得客户端自己把图压缩并跟着消息传出去,那也不要浪费了这个数据,我先尝试了方法1.
方法1:
①尝试直接把取到的uri toString和getPath()的值存到数据库,取出来转成uri再转成drawable失败,想来是因为融云给的这个uri里面包含了其他关键参数;
②尝试把uri整个用gson转成json格式的string存到数据库,这个过程折腾了一下,Uri到String正常,String到uri的时候报
Failed to invoke private android.net.Uri() with no args
查了一下发现要通过两个实现自JsonDeserializer和JsonSerializer的类来解决这个问题。代码如下
public class UriSerializer implements JsonSerializer<Uri> {
public JsonElement serialize(Uri src, Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
}
public class UriDeserializer implements JsonDeserializer<Uri> {
@Override
public Uri deserialize(final JsonElement src, final Type srcType,
final JsonDeserializationContext context) throws JsonParseException {
return Uri.parse(src.getAsString());
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriSerializer())
.create();
str = gson.toJson(oModel));
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriDeserializer())
.create();
mOrderModel = gson.fromJson(str, FModel.class);
③解决完之后又发现一个问题,由于我是在统一的一个地方接收消息并处理,之后再以广播的形式发出去相关页面接收,改了之后发现广播全部接收不到。
检查之后发现还是Uri的问题,Uri是不能序列化的,所以广播发不出去。
本来是想通过写一个继承自Uri的类并实现序列化接口来解决,后来突然想到这个图片按照他们的说法是放在客户端本地的某个地方,万一这个环境变了,那图片就丢了,所以干脆抛弃存uri的这个方案
方法2:
抓取融云给的原图Url之后发现,他们的图片是需要验证访问的,参数中加了类似token的一些信息,想要按照我所知道的处理七牛图片的方法(在url加参数)来处理无从下手,随便测了几下果然不能用,询问融云的开发后得到的答案是他们为了安全所以加限制,暂时也没有可以让客户端自定义图片大小的想法,所以这个方案作罢。
方法3:
其实刚开始的时候就有这个想法,只不过一直觉得数据库寸一堆字节流貌似会有点大,而且还存在一个转换过程会损耗一点点性能,不过现在权衡了一下好像只能这么做了。
drawable和string互转的代码网上很多就不贴了,基本思路是drawable转bitmap,然后通过字节输出流转成字节流,之后再用base64编码成string;
反向的话就直接从string用base64解码成字节流,再通过BitmapFactory.decodeByteArray,就搞定了。
总结:
1.Uri和String格式的Json数据互转需要JsonDeserializer
和JsonSerializer
来辅助。
2.带Uri属性的对象不能直接发送广播,也许通过序列化Uri的一个类可以实现。
3.有些文件需要存起来的话,可以考虑转成字节流的形式进行持久化。