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

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

Android 性能优化<八> 多线程优化和线程管理

https://blog.csdn.net/WHB20081815/article/details/77775444

Android 性能优化 <九>RecyclerView替代Listview用法

https://blog.csdn.net/WHB20081815/article/details/76221998

Android 性能优化 (十) 启动优化 秒变大神 启动优化提升60%

https://blog.csdn.net/WHB20081815/article/details/88595045

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把读取到的东西写入到那个目录.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值