Android性能优化之三 数据格式优化

        Android性能优化之一 数据存储优化

        Android性能优化之二 代码优化

        Android性能优化之三 数据格式优化

        目前读取的数据文件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数据,在以后读取数据时做解析文件使用。

代码地址:https://github.com/androidmi/Toy        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值