关于Android开发中Java对象序列化的一次测试
转载自: http://bxbxbai.gitcafe.io/2015/05/05/a-serializable-test/
Android开发过程中会遇到很多情况,需要将一个Java序列化,比如序列化一个对象来保存当前一些信息,等下次App启动后再还原。
对象序列化可以有好多种方法,一般最简单的就是实现Serializable
接口,通过ObjectOutputStream
写到SD卡中;还有可以将Java对象序列化到数据库中;还可以将Java对象转成一个字符串,把这个字符串写到SD卡中,反序列化时读取这个字符串,并且转成一个Java对象。
如果只保存一个Java对象,你应该不会把它写到数据库中的,一般会使用另外两种方法,但是那种方法好呢?
方法0:实现Serializable接口
写上两段代码
//将Object写入SD卡
private void writeObject(Object result) {
ObjectOutputStream oos = null;
FileOutputStream fileOutputStream = null;
try {
File file = new File(Config.getCachePath() + "bxbxbai");
fileOutputStream = new FileOutputStream(file);
oos = new ObjectOutputStream(fileOutputStream);
oos.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//读取Object
private Object readObject() {
Object object = null;
File file = new File(Config.getCachePath() + "bxbxbai");
if (file.isFile()) {
ObjectInputStream ois = null;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
ois = new ObjectInputStream(fileInputStream);
object = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fileInputStream.close();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return object;
}
return null;
}
方法1:将对象转换成String序列化
//先用Gson将对象转换成String,然后把String写入SD卡private void writeObjectString(Object result) {
String s = new Gson().toJson(result);
FileOutputStream fileOutputStream = null; try { File file = new File(Config.getCachePath() + "bxbxbai_string");
fileOutputStream = new FileOutputStream(file);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fileOutputStream));
writer.write(s);
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
} finally { try {
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}//先读取String,然后转成Java对象private Object readObjectString() { File file = new File(Config.getCachePath() + "bxbxbai_string"); if (file.isFile()) { try {
Scanner scanner = new Scanner(file);
StringBuilder json = new StringBuilder(); while (scanner.hasNext()) {
json.append(scanner.nextLine());
}
scanner.close(); return new Gson.fromJson(json.toString(), SerializeStringResult.class);
} catch (Exception e) {
e.printStackTrace();
}
} return null;
}
测试
基本的功能代码已经都贴了,下面是测试代码:
private void test() { try { //省略创建object代码,result0 和result1 完全一样
StopWatch.begin("writeObject");
writeObject(result0);
StopWatch.end("writeObject");
StopWatch.begin("readObject");
Object o1 = readObject();
StopWatch.end("readObject"); //写String
StopWatch.begin("writeObjectString");
writeObjectString(result1);
StopWatch.end("writeObjectString");
StopWatch.begin("readObjectString");
Object o2 = readObjectString();
StopWatch.end("readObjectString");
} catch (Exception e) {
e.printStackTrace();
}
}
测试数据是地址:地址,测试手机使用LG-D858
一共测试了10次,平均结果如下:
-
Serializable写:282ms
-
Serializable读:104ms
-
转String写:30ms
-
转String读:61ms
也就是说将Java对象转成String再进行序列化以及反序列化可以大大减少时间。
Once upon a time, this used the standard Java Object{Input,Output}Stream, but the default implementation relies heavily on reflection (even for standard types) and generates a ton of garbage.
上面这段话是我几个月前我看Volley源码的时候看到的,在DiskBasedCache
类中,大致的意思就是之前Volley也是用Java对象的序列化来缓存HTTP 头信息的,后来发现Object{Input,Output}Stream
序列化严重依赖反射机制,会在序列化过程中产生大量的临时对象,从而更加频繁的触发GC,后来Google的工程师自己写了一个简单的序列化和反序列化方法
总结
从测试结果中可以看到,将Java对象转换成String,然后在把String序列化可以节省大量的时间。不仅如此,Object{Input,Output}Stream
序列化方法严重依赖Java反射机制,在序列化过程中会产生大量的临时对象,会更加频繁的触发GC操作
所以,我觉得还是把Java对象转成String再序列化吧,可以提升不少性能呢 :)
2015.05.07 更新
我这个是测试这两个序列化方法的性能。注意一下,Gson库将一个Java对象转成字符串也是使用Java反射的,如果某些场景需要更高的性能,那么需要自己写序列化方法。
比如,参考Parcelable
接口,我们自己写代码,将对象转换成字符串(而不是依赖Gson库来转成字符串)序列化,以及相应的反序列化。或许你还想到了其他更好的方法,希望你能和我分享讨论~ :)