Android性能优化汇总
简单一句概括:用字节流代替JSON进行网络传输,提示效率(速度、大小)
一 FlatBuffer使用原有
在做 Android 开发的时候,JSON 是最常用的数据序列化技术。JSON 的可读性很强,但是序列化和反序列化性能却是最差的。解析的时候,JSON 解析器首先,需要在内存中初始化一个对应的数据结构,这个事件经常会消耗 100ms ~ 200ms2;解析过程中,要产生大量的临时变量,造成 Java 虚拟机的 GC 和内存抖动,解析 20KB 的数据,大概会消耗 100KB 的临时内存2。FlatBuffers 就解决了这些问题
二 FlatBuffer
FlatBuffers 是一个开源的跨平台数据序列化库,可以应用到几乎任何语言(C++, C#, Go, Java, JavaScript, PHP, Python),最开始是 Google 为游戏或者其他对性能要求很高的应用开发的。项目地址在 GitHub 上。官方的文档在 这里。
- 直接读取序列化数据,而不需要解析(Parsing)或者解包(Unpacking):FlatBuffer 把数据层级结构保存在一个扁平化的二进制缓存(一维数组)中,同时能够保持直接获取里面的结构化数据,而不需要解析,并且还能保证数据结构变化的前后向兼容
- 高效的内存使用和速度:FlatBuffer 使用过程中,不需要额外的内存,几乎接近原始数据在内存中的大小
- 灵活:数据能够前后向兼容,并且能够灵活控制你的数据结构。
- 很少的代码侵入性:使用少量的自动生成的代码即可实现。
- 强数据类性,易于使用,跨平台,几乎语言无关。
性能对比
三 使用
1 编写Model对应的fbs文件
Items.fbs
namespace com.bpj.optimization.optimization.lsn13;
table Items {
ItemId : long;
timestemp : int;
basic:[Basic];
}
table Basic{
id:int;
name:string;
email:int;
code:long;
isVip:bool;
count:int;
carList:[Car];
}
table Car{
id:long;
number:long;
describle:string;
}
root_type Items;
2 当前目录下,命令行编译生成java文件
flatc -j -b fbs文件名.fbs
生成对应的java文件:
3 拷贝java文件到项目中使用
同时拷贝的还有库提供的FlatBufferBuilder.java 和Table.java文件,修改报错
4 使用
public void serialize(View v) {
new Thread(new Runnable() {
@Override
public void run() {
//==================序列化========================
FlatBufferBuilder builder = new FlatBufferBuilder();
int id1 = builder.createString("兰博基尼");
//准备Car对象
int car1 = Car.createCar(builder, 10001L, 88888L, id1);
int id2 = builder.createString("奥迪A8");
//准备Car对象
int car2 = Car.createCar(builder, 10001L, 88888L, id2);
int id3 = builder.createString("奥迪A9");
//准备Car对象
int car3 = Car.createCar(builder, 10001L, 88888L, id3);
int[] cars = new int[3];
cars[0] = car1;
cars[1] = car2;
cars[2] = car3;
//创建Basic对象里面的Car集合
int carList = Basic.createCarListVector(builder, cars);
int name = builder.createString("ray");
int email = builder.createString("ray@qq.com");
int basic = Basic.createBasic(builder, 10, name, email, 100L, true, 100, carList);
int basicOffset = Items.createBasicVector(builder, new int[]{basic});
/**
* table Items {
ItemId : long;
timestemp : int;
basic:[Basic];
}
*/
Items.startItems(builder);
Items.addItemId(builder, 1000L);
Items.addTimestemp(builder, 2016);
Items.addBasic(builder, basicOffset);
int rootItems = Items.endItems(builder);
Items.finishItemsBuffer(builder, rootItems);
//============保存数据到文件=================
if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
Log.e(TAG, "sdcard un MEDIA_MOUNTED");
}
File sdcard = Environment.getExternalStorageDirectory();
//保存的路径
File file = new File(sdcard, "Items.txt");
if (file.exists()) {
file.delete();
}
ByteBuffer data = builder.dataBuffer();
FileOutputStream out = null;
FileChannel channel = null;
try {
out = new FileOutputStream(file);
channel = out.getChannel();
while (data.hasRemaining()) {
channel.write(data);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (channel != null) {
channel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//===================反序列化=============================
FileInputStream fis = null;
FileChannel readChannel = null;
try {
fis = new FileInputStream(file);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
readChannel = fis.getChannel();
int readBytes = 0;
while ((readBytes = readChannel.read(byteBuffer)) != -1) {
System.out.println("读取数据个数:" + readBytes);
}
//把指针回到最初的状态,准备从byteBuffer当中读取数据
byteBuffer.flip();
//解析出二进制为Items对象。
Items items = Items.getRootAsItems(byteBuffer);
//读取数据测试看看是否跟保存的一致
Log.i(TAG, "items.id:" + items.ItemId());
Log.i(TAG, "items.timestemp:" + items.timestemp());
Basic basic2 = items.basic(0);
Log.i(TAG, "basic2.name:" + basic2.name());
Log.i(TAG, "basic2.email:" + basic2.email());
//carList
int length = basic2.carListLength();
for (int i = 0; i < length; i++) {
Car car = basic2.carList(i);
Log.i(TAG, "car.number:" + car.number());
Log.i(TAG, "car.describle:" + car.describle());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (readChannel != null) {
readChannel.close();
}
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}