描述
由于我利用Gson和ActiveAndroid来保存数据,之前已经能顺利保存各种自定义类型。今天添加一种新的List自定义类型,之后sqlite疯狂报错,插入出现键重复:
我很清楚的记得以前绝对没这错误,而且这条数据绝对存在。
为啥用ActiveAndroid的Select出来是null? 我百思不得其解,由于一口气改了太多地方,一度怀疑是事务引起的,由于我用两个线程同时在加载数据,可能一个线程插入了,另一个线程也在操作这数据,就怀疑ActiveAndroid的事务实现有bug。
但是很快就排除了,因为数据库如果没这数据就算报错也应该有把数据插入成功的log,但是只有1条报错的log。说明数据库原来就有这数据。那么就是Select的问题。
通过仔细比较数据,发现有List<\String> picUrls的才会出错。就怀疑是不是数据有问题。
调试
怀疑是序列化出了问题,因为我改过这里。
public class ListStringSerializer extends TypeSerializer {
@Override
public Class<?> getDeserializedType() {
return List.class;
}
@Override
public Class<?> getSerializedType() {
return String.class;
}
@Override
public String serialize(Object o) {
// List<String> List<AtUser> List和T均可直接toString
if (o == null) {
return null;
}
// Log.i("ListStringSerializer",o.toString());
return o.toString();
}
@Override
public List<String> deserialize(Object o) {
if (o == null) {
return null;
}
Log.i("ListStringSerializer","deserialize:" + o.toString());
List<String> ret = null;
try {
ret = new Gson().fromJson((String) o,new TypeToken<List<String>>() {
}.getType());
} catch (Exception ex) {
Log.e("ListStringSerializer",Log.getStackTraceString(ex));
}
Log.i("ListStringSerializer","deserialize ret:" + ret);
return new Gson().fromJson((String) o,new TypeToken<List<String>>() {}.getType());
}
}
这下终于报错了:
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated array。
就能确定是数据的问题,导致无法正确序列号。坑爹的是ActiveAndroid对这个反序列化异常不打log也不报错,只是返回一个null。
这是原来的序列化代码:
import android.util.Log;
import com.activeandroid.serializer.TypeSerializer;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.List;
public class ListStringSerializer extends TypeSerializer {
@Override
public Class<?> getDeserializedType() {
return List.class;
}
@Override
public Class<?> getSerializedType() {
return String.class;
}
@Override
public String serialize(Object o) {
if (o == null) {
return null;
}
return new Gson().toJson(o); // ["string"]
}
@Override
public List<String> deserialize(Object o) {
if (o == null) {
return null;
}
return new Gson().fromJson((String) o,new TypeToken<List<String>>(){}.getType());
}
}
我今天蛋疼的把这里改了:
@Override
public String serialize(Object o) {
if (o == null) {
return null;
}
return o.toString(); // [string]
}
Gson对Json的语法检查还是很严格的,toString导致括号内的String少一对引号,所以不能被识别为String类型。
总结
这个Bug之所以难调,是因为数据库里面有残留的错误格式的数据,导致Select一直为Null。我最开始就了怀疑这里,就把代码改回原样子,只是当时没有把数据库删除,导致残留数据无法select,发现Bug依然存在。就把这里排除掉了。真是没想到为啥ActiveAndroid对这里的异常不打Log,其他地方都打了。 最蛋疼的Java编程风格就是一个try-catch把异常都吃了,搞得出问题无从调试。所以宁愿每个函数后面都带throw也不要自己在中间过程的函数中吃了异常。