在Android应用不断升级的今天,一款应用要实现特定的功能,需要读取预先生成的数据包,或者通过网络下载的方式获取数据,目的是使用户在第一次使用应用时这些数据就可以为用户服务。
将所有文件内容读取到String中,使用Android自带的JSON类库进行解析,然后逐条将数据插入数据库中:
本文主要讨论的是上面提到的数据包在应用使用过程中数据存储和读取的优化。
案例:本应用主要是为某玩具公司制作销售管理系统的客户端,方便管理人员定时查看玩具的生产和销售情况。该应用需要显示的玩具分类情况,有四种数据需要进行记录,如下所示:
- 产品序号(serial):字符型不会重复
- 类别(sort):产品的分类,有 "经营策略", "动作竞技", "体育竞技", "休闲益智", "网络模拟","射击冒险"6种类别。
- 数量(amount):产品目前的库存
- 销量(distribute):产品目前的销售情况
数据存储选用JSON格式保存数据,格式如下:
{['serial':'51105386080','sort':'体育竞技','amount':139'distribute':5],
['serial':'68156206434','sort':'经营策略','amount':58'distribute':28]}
当用户第一次安装应用时,数据包需要带入主包中,为了方便调用,我们最终将数据插入数据库中,然后直接从数据库中取用数据。创建数据库:
public static ToyDatabaseHelper getInstance(Context context) {
if (sInstance == null) {
sInstance = new ToyDatabaseHelper(context.getApplicationContext());
}
return sInstance;
}
public void insertRecord(ContentValues values) {
SQLiteDatabase db = null;
try {
db = getWritableDatabase();
db.insert(RecordTable.TABLE_NAME, null, values);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDatabase(db);
}
}
public void deleteAllRecord() {
SQLiteDatabase db = null;
try {
db = getWritableDatabase();
db.delete(RecordTable.TABLE_NAME, null, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDatabase(db);
}
}
@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 + " TEXT NOT NULL,");
sb.append(RecordTable.COLUMN_AMOUNT + " INTEGER NOT NULL,");
sb.append(RecordTable.COLUMN_DISTRIB + " INTEGER NOT NULL");
sb.append(");");
db.execSQL(sb.toString());
}
将文件放入/assert文件夹中然后使用代码读取文件
InputStream in = getContext().getAssets().open("recode.txt");
int available = in.available();
byte[] buffer = new byte[available];
in.read(buffer);
String json = new String(buffer);
将所有文件内容读取到String中,使用Android自带的JSON类库进行解析,然后逐条将数据插入数据库中:
JSONArray array = new JSONArray(json);
long start = System.currentTimeMillis();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
String serial = obj.getString("serial");
String sort = obj.getString("sort");
int amount = obj.getInt("amount");
int distribute = obj.getInt("distribute");
ContentValues values = new ContentValues();
values.put(RecordTable.COLUMN_SERIAL, serial);
values.put(RecordTable.COLUMN_AMOUNT, amount);
values.put(RecordTable.COLUMN_SORT, sort);
values.put(RecordTable.COLUMN_DISTRIB, distribute);
mToyDatabaseHelper.insertRecord(values);
}
此时测试,20000条数据插入数据库需要974097ms,超过一分半钟。由于此时读入的数据也占用了很多的内存所以需要继续优化。
接下来的优化目的是减少数据插入数据库的时间:
在SQL数据处理时,可以使用事物机制(Transaction),事物机制就是将所有的操作一次性提交,可以大大的较少数据库的操作时间,但事物也有弊端,如果有一条提交失败,所有的提交都会失败,所以要确保数据源的正确性。
修改数据库的插入方式,直接使用JSONArray作为数据源进行处理,使用数据一次性提交代码
public void insertRecordWithJSONArray(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++) {
JSONObject obj = array.getJSONObject(i);
String serial = obj.getString("serial");
String sort = obj.getString("sort");
int amount = obj.getInt("amount");
int distribute = obj.getInt("distribute");
ContentValues values = new ContentValues();
values.put(RecordTable.COLUMN_SERIAL, serial);
values.put(RecordTable.COLUMN_AMOUNT, amount);
values.put(RecordTable.COLUMN_SORT, sort);
values.put(RecordTable.COLUMN_DISTRIB, distribute);
db.insert(RecordTable.TABLE_NAME, null, values);
}
db.setTransactionSuccessful();
db.endTransaction();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeDatabase(db);
}
}
直接调用array参数的插入接口:
mToyDatabaseHelper.insertRecordWithJSONArray(array);
测试时间6578ms,相比与之前的974097ms速度已经提升了15倍。
后续文章将针对本次示例进行代码和数据量方面的重构和优化。