Android 性能优化 (二)数据库优化 秒变大神

来源:互联网 发布:unity3d 录屏插件 编辑:程序博客网 时间:2024/06/05 05:14


 

Android 性能优化 (一)APK高效瘦身


http://blog.csdn.net/whb20081815/article/details/70140063

Android 性能优化 (二)数据库优化 秒变大神
http://blog.csdn.net/whb20081815/article/details/70142033
 

Android 性能优化(三)布局优化 秒变大神


http://blog.csdn.net/whb20081815/article/details/70147958

 Android 性能优化(四)内存优化OOM 秒变大神
 http://blog.csdn.net/whb20081815/article/details/70243105
Android 性能优化(五)ANR 秒变大神
http://blog.csdn.net/whb20081815/article/details/70245594
Android 性能优化(六) RelativeLayout和LinearLayout性能比较
http://blog.csdn.net/whb20081815/article/details/74465870
 

Android 性能优化<七>自定义view绘制优化


http://blog.csdn.net/whb20081815/article/details/74474736


1.数据库插入效率

 有三种方法:
1)直接拼接SQL语句,执行execSQL方法;
2)借用ContentValues进行插入;
3)使用compileStatement进行插入;

1)直接拼接SQL语句,执行execSQL方法, 一个一个插入

/** * 向表中插入数据 * * @param openHelper * @param appInfo * @return */public static boolean insert(SQLiteOpenHelper openHelper,                           RemoteAppInfo appInfo) {    if (null == appInfo) {        return true;    }    SQLiteDatabase db = null;    try {        db = openHelper.getWritableDatabase();        ContentValues values = appInfo.getContentValues();        return -1 != db.insert(RemoteDBHelper.TABLE_APP_REMOTE, null,                values);    } catch (Exception e) {        e.printStackTrace();    } finally {        if (null != db) {            db.close();        }    }    return false;}for (RemoteAppInfo remoteAppInfo : list){    RemoteDBUtil.insert(helper, remoteAppInfo);}

public void execSQL(){    String sql = "create table msgTable(uid INTEGER NOT NULL,  msg TEXT NOT NULL)";    db.execSQL(sql);}
缺点:存在SQL注入危险;

查看源码得出:execSQL调用的本质就是创建SQLiteStatement对象,调用其executeUpdateDelete插入方法


  1.利用android提高的的insert,query,update,deleteAPI与execSql,rawQuery函数执行原生的插入,查询,更新,删除语句操作花费时间的对比结果


    在相同的环境(adnroid4.0)和相同的机器下执行相同的动作,记录条数也一样的情况下的对比,多次验证的如下:

    (1)如果批量执行的记录数在1000条,则Android SqliteDatabase提供的insert,query,update,delete函数和直接写SQL文的execSql,rawQuery的效率差不多,几乎一样。所以使用哪种方式都可以,不会影响到执行效率。

    (2)如果批量执行的记录数在10万条,则会存在差别。在某台手机上SqliteDatabase提供的insert执行插入操作耗时45秒,要比execSql插入35秒慢10秒左右。

    可见在数据库大的情况下,还是有差别的。execSql省去了拼接sql语句的步骤,要比SqliteDatabase提供的insert,query,update,delete等函数效率高。当数据库越大,差别也越大。


二.开启事务批量插入,借用ContentValues;

这样如果连续插入100次数据实际是创建事务->执行语句->提交这个过程被重复执行了100次。如果我们显示的创建事务->执行100条语句->提交会使得这个创建事务和提交这个过程只做一次,通过这种一次性事务可以使得性能大幅提升。尤其当数据库位于sd卡时,时间上能节省两个数量级左右。

/** * 向表中插入一串数据 * * @param openHelper * @param appInfo * @return 如果成功则返回true,否则返回flase */public static boolean insert(SQLiteOpenHelper openHelper,                           List<RemoteAppInfo> list) {    boolean result = true;    if (null == list || list.size() <= 0) {        return true;    }    SQLiteDatabase db = null;    try {        db = openHelper.getWritableDatabase();        db.beginTransaction();        for (RemoteAppInfo remoteAppInfo : list) {            ContentValues values = remoteAppInfo.getContentValues();            if (db.insert(RemoteDBHelper.TABLE_APP_REMOTE, null, values) < 0) {                result = false;                break;            }        }        if (result) {            db.setTransactionSuccessful();        }    } catch (Exception e) {        e.printStackTrace();        return false;    } finally {        try {            if (null != db) {                db.endTransaction();                db.close();            }        } catch (Exception e) {            e.printStackTrace();        }    }    return true;}
借用ContentValues进行插入,解决了执行纯SQL语句引入的sql注入漏洞。

源码分析:使用ContentValues 最终是创建SQLiteStatement对象,并调用executeInsert()方法。

三,compileStatement,开启事务批量插入,使用SQLiteStatement

public static boolean insertBySql(SQLiteOpenHelper openHelper,                                List<RemoteAppInfo> list) {    if (null == openHelper || null == list || list.size() <= 0) {        return false;    }    SQLiteDatabase db = null;    try {        db = openHelper.getWritableDatabase();        String sql = "insert into " + RemoteDBHelper.TABLE_APP_REMOTE + "("                + RemoteDBHelper.COL_PKG_NAME + ","// 包名                + RemoteDBHelper.COL_USER_ACCOUNT + ","// 账号                + RemoteDBHelper.COL_APP_SOURCE + ","// 来源                + RemoteDBHelper.COL_SOURCE_UNIQUE + ","// PC mac 地址                + RemoteDBHelper.COL_MOBILE_UNIQUE + ","// 手机唯一标识                + RemoteDBHelper.COL_IMEI + ","// 手机IMEI                + RemoteDBHelper.COL_INSTALL_STATUS + ","// 安装状态                + RemoteDBHelper.COL_TRANSFER_RESULT + ","// 传输状态                + RemoteDBHelper.COL_REMOTE_RECORD_ID // 唯一标识                + ") " + "values(?,?,?,?,?,?,?,?,?)";        SQLiteStatement stat = db.compileStatement(sql);        db.beginTransaction();        for (RemoteAppInfo remoteAppInfo : list) {            stat.bindString(1, remoteAppInfo.getPkgName());            stat.bindString(2, remoteAppInfo.getAccount());            stat.bindLong(3, remoteAppInfo.getFrom());            stat.bindString(4, remoteAppInfo.getFromDeviceMd5());            stat.bindString(5, remoteAppInfo.getMoblieMd5());            stat.bindString(6, remoteAppInfo.getImei());            stat.bindLong(7, remoteAppInfo.getInstallStatus());            stat.bindLong(8, remoteAppInfo.getTransferResult());            stat.bindString(9, remoteAppInfo.getRecordId());            long result = stat.executeInsert();            if (result < 0) {                return false;            }        }        db.setTransactionSuccessful();    } catch (Exception e) {        e.printStackTrace();        return false;    } finally {        try {            if (null != db) {                db.endTransaction();                db.close();            }        } catch (Exception e) {            e.printStackTrace();        }    }    return true;}

SQLiteStatement stat = TelSqlAdapter.getInstance().getSqliteDb().compileStatement(sql);

小结:对于执行纯sql,ContentValues和compileStatement最终都是new 一个SQLiteStatement对象,并调用SQLiteStatement对象的相应方法。

无论哪种方法的话,都会用SQLiteStatement,直接用这个看,

=========================================

其他方式:

1)。语句的拼接使用StringBuilder代替String

简单的string相加会导致创建多个临时对象消耗性能。StringBuilder的空间预分配性能好得多。如果你对字符串的长度有大致了解,如100字符左右,可以直接new StringBuilder(128)指定初始大小,减少空间不够时的再次分配。

2)。少用cursor.getColumnIndex

根据性能调优过程中的观察cursor.getColumnIndex的时间消耗跟cursor.getInt相差无几。可以在建表的时候用static变量记住某列的index,直接调用相应index而不是每次查询。


3)。查询条件多点限制,查表就速度快


提问:

1.数据库的操作类型有哪些,如何导入外部数据库?


    把原数据库包括在项目源码的 res/raw。android系统下数据库应该存放在 /data/data/com..(package name)/ 目录下,所以我们需要做的是把已有的数据库传入那个目录下.操作方法是用FileInputStream读取原数据库,再用FileOutputStream把读取到的东西写入到那个目录.



0 0
原创粉丝点击