目前读取的数据文件record.txt有20000条数据,占用空间1.5M,因为该数据需要内置进apk,所以对产品来说是不能接收apk文件随意增加1M以上容量的,所以我们需要对数据进行分析,最终调整数据格式,目的是减少文件大小,但不能影响功能。
先分析一下数据格式,目前数据采用的是JSON格式中的对象存储(/assets/record.txt):
[{'serial':'85538352166','sort':'动作竞技','amount':54,'distribute':0},{'serial':'74722873748','sort':'体育竞技','amount':165,'distribute':16},...]
该数据能明确表达数据的意图,从而方便开发人员理解和解析,缺点也是显而易见的每组数据中的key总是保持不变,变化的只有value值。所以object数据会存在大量的数据冗余,该数据冗余部分已经大大超过了有效数据部分,所以需要针对该特点对数据进行分析和处理。
需要将冗余部分的数据去掉:
[['85538352166','动作竞技',54,0],['74722873748','体育竞技',165,16],...]
优化后的文件record_opt1.txt占用空间762k,体积减少了50%.
数据格式调整,数据的解析和存储方式也需要调整。首先遵循OPC原则,增加RecodeModel中对JSONArray数据的解析方式:
private static final int SERIAL = 0;
private static final int SORT = 1;
private static final int AMOUNT = 2;
private static final int DISTRIBUTE = 3;
/**
* @param array
* [['85538352166','动作竞技',54,0],['74722873748','体育竞技',165,16],...]
* @return
*/
public static RecodeModel createFromJson(JSONArray array) {
try {
RecodeModel model = new RecodeModel();
model.serial = array.getString(SERIAL);
model.sort = array.getString(SORT);
model.amount = array.getInt(AMOUNT);
model.distribute = array.getInt(DISTRIBUTE);
return model;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
然后增加针对该数据格式的插入操作:
public void insertRecordWithOpt1JSONArray(JSONArray array) {
if (array == null || array.length() == 0) {
return;
}
SQLiteDatabase db = null;
try {
db = getWritableDatabase();
db.beginTransaction();
for (int i = 0; i < array.length(); i++) {
JSONArray arr = array.getJSONArray(i);
RecodeModel mode = RecodeModel.createFromJson(arr);
ContentValues values = new ContentValues();
values.put(RecordTable.COLUMN_SERIAL, mode.getSerial());
values.put(RecordTable.COLUMN_AMOUNT, mode.getAmount());
values.put(RecordTable.COLUMN_SORT, mode.getSort());
values.put(RecordTable.COLUMN_DISTRIB, mode.getDistribute());
db.insert(RecordTable.TABLE_NAME, null, values);
}
db.setTransactionSuccessful();
db.endTransaction();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDatabase(db);
}
}
在测试项目中增加对新数据的解析和读取
public void testOpt1RecordInsertWithArray() {
mToyDatabaseHelper.deleteAllRecord();
JSONArray array = FileUtils.getJSONArrayFromAssets(getContext(), "record_opt1.txt");
Log.i(TAG, "start testOpt1RecordInsertWithArray");
Log.i(TAG, "length:" + array.length());
long start = System.currentTimeMillis();
mToyDatabaseHelper.insertRecordWithOpt1JSONArray(array);
long duration = System.currentTimeMillis() - start;
Log.i(TAG, "duration:" + duration);
}
现在回头看看已经优化的数据:
[['85538352166','动作竞技',54,0],['74722873748','体育竞技',165,16],...]
注意‘动作竞技’,‘体育竞技’等数据,在本系列文章第一篇中有说明,游戏公司的游戏种类是特定的,其他销售数据会变动,所以针对不变的数据,建立映射关系:
'1':'动作竞技','2':'体育竞技','3':'经营策略','4':休闲益智
使用数字来代替文字,修改后文件格式如下:
{'mapping':{'1':'动作竞技','2':'体育竞技','3':'经营策略','4':休闲益智},'data':[['85538352166',1,54,0],...]}
修改后的文件record_opt2.txt占用空间502KB
此时sort的类型修改为int型,修改数据库字段类型
@Override
public void onCreate(SQLiteDatabase db) {
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE ");
sb.append(RecordTable.TABLE_NAME);
sb.append(" (");
sb.append(BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, ");
sb.append(RecordTable.COLUMN_SERIAL + " TEXT UNIQUE NOT NULL,");
sb.append(RecordTable.COLUMN_SORT + " INTEGER NOT NULL,");
sb.append(RecordTable.COLUMN_AMOUNT + " INTEGER NOT NULL,");
sb.append(RecordTable.COLUMN_DISTRIB + " INTEGER NOT NULL");
sb.append(");");
db.execSQL(sb.toString());
}
数据格式修改,在数据读取时需要增加RecodeDataModel.java中间类,在不修改RecodeModel.java的情况下对数据进行处理
public class RecodeDataModel {
private String mMapping;
private JSONArray mData;
public String getMapping() {
return mMapping;
}
public JSONArray getData() {
return mData;
}
private RecodeDataModel() {
}
public static RecodeDataModel createFromJson(JSONObject obj) {
RecodeDataModel model = new RecodeDataModel();
try {
model.mMapping = obj.getString("mapping");
model.mData = obj.getJSONArray("data");
return model;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
}
修改数据读取和存储代码
/**
* 动作竞技 1 体育竞技 2 经营策略 3 休闲益智 4
*/
public void testOptRecordInsertWithArray() {
ToyApplication.init(getContext());
ToyOptDatabaseHelper dbHelper = ToyOptDatabaseHelper.getInstance(getContext());
dbHelper.deleteAllRecord();
JSONObject obj = FileUtils.getJSONObjectFromAssets(getContext(), "record_opt2.txt");
assertNotNull(obj);
RecodeDataModel model = RecodeDataModel.createFromJson(obj);
JSONArray array = model.getData();
String mapping = model.getMapping();
// store mapping data
ToyApplication.setRecodeMapping(mapping);
Log.i(TAG, "start testOptRecordInsertWithArray");
long start = System.currentTimeMillis();
dbHelper.insertRecordWithOpt1JSONArray(array);
long duration = System.currentTimeMillis() - start;
Log.i(TAG, "duration:" + duration);
}
红色代码保存mapping数据,在以后读取数据时做解析文件使用。