当前位置:   article > 正文

Kotlin入门(26)数据库ManagedSQLiteOpenHelper_kotlin managedsqliteopenhelper.

kotlin managedsqliteopenhelper.

共享参数毕竟只能存储简单的键值对数据,如果需要存取更复杂的关系型数据,就要用到数据库SQLite了。尽管SQLite只是手机上的轻量级数据库,但它麻雀虽小、五脏俱全,与Oracle一样存在数据库的创建、变更、删除、连接等DDL操作,以及数据表的增删改查等DML操作,因此开发者对SQLite的使用编码一点都不能含糊。当然,Android为了方便开发者的工作,已经提供了一个操作SQLite的工具类即SQLiteOpenHelper,在App开发时可由SQLiteOpenHelper派生出具体的业务表管理类。
但是,系统自带的SQLiteOpenHelper有个先天缺陷,就是它并未封装数据库管理类SQLiteDatabase,这造成一个后果:开发者需要在操作表之前中手工打开数据库连接,然后在操作结束后手工关闭数据库连接。可是手工开关数据库连接存在着诸多问题,比如数据库连接是否重复打开了?数据库连接是否忘记关闭了?在A处打开数据库却在B处关闭数据是否造成业务异常?以上的种种问题都制约了SQLiteOpenHelper的安全性。
有鉴于此,Kotlin结合Anko库推出了改良版的SQLite管理工具,名叫ManagedSQLiteOpenHelper,该工具封装了数据库连接的开关操作,使得开发者完全无需关心SQLiteDatabase在何时在何处调用,也就避免了手工开关数据库连接可能导致的各种异常。同时ManagedSQLiteOpenHelper的用法与SQLiteOpenHelper几乎一模一样,唯一的区别是:数据表的增删改查语句需要放在use语句块之中,具体格式如下:

  1.     use {
  2.         //1、插入记录
  3.         //insert(...)
  4.         //2、更新记录
  5.         //update(...)
  6.         //3、删除记录
  7.         //delete(...)
  8.         //4、查询记录
  9.         //query(...)或者rawQuery(...)
  10.     }

其中表的查询操作还要借助于SQLite已有的游标类Cursor来实现,上述代码中的query和rawQuery方法,返回的都是Cursor对象,那么获取查询结果就得根据游标的指示一条一条遍历结果集合。下面是Cursor类的常用方法:
1、游标控制类方法,用于指定游标的状态:
close : 关闭游标
isClosed : 判断游标是否关闭
isFirst : 判断游标是否在开头
isLast : 判断游标是否在末尾
2、游标移动类方法,把游标移动到指定位置:
moveToFirst : 移动游标到开头
moveToLast : 移动游标到末尾
moveToNext : 移动游标到下一个
moveToPrevious : 移动游标到上一个
move : 往后移动游标若干偏移量
moveToPosition : 移动游标到指定位置
3、获取记录类方法,可获取记录的数量、类型以及取值。
getCount : 获取记录数
getInt : 获取指定字段的整型值
getFloat : 获取指定字段的浮点数值
getString : 获取指定字段的字符串值
getType : 获取指定字段的字段类型
接下来以用户注册信息数据库为例,看看Kotlin的数据库操作代码是怎样实现的,具体的实现代码示例如下:

  1. class UserDBHelper(var context: Context, private var DB_VERSION: Int=CURRENT_VERSION) : ManagedSQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
  2.     companion object {
  3.         private val TAG = "UserDBHelper"
  4.         var DB_NAME = "user.db" //数据库名称
  5.         var TABLE_NAME = "user_info" //表名称
  6.         var CURRENT_VERSION = 1 //当前的最新版本,如有表结构变更,该版本号要加一
  7.         private var instance: UserDBHelper? = null
  8.         @Synchronized
  9.         fun getInstance(ctx: Context, version: Int=0): UserDBHelper {
  10.             if (instance == null) {
  11.                 //如果调用时没传版本号,就使用默认的最新版本号
  12.                 instance = if (version>0) UserDBHelper(ctx.applicationContext, version)
  13.                             else UserDBHelper(ctx.applicationContext)
  14.             }
  15.             return instance!!
  16.         }
  17.     }
  18.     override fun onCreate(db: SQLiteDatabase) {
  19.         Log.d(TAG, "onCreate")
  20.         val drop_sql = "DROP TABLE IF EXISTS $TABLE_NAME;"
  21.         Log.d(TAG, "drop_sql:" + drop_sql)
  22.         db.execSQL(drop_sql)
  23.         val create_sql = "CREATE TABLE IF NOT EXISTS $TABLE_NAME (" +
  24.             "_id INTEGER PRIMARY KEY  AUTOINCREMENT NOT NULL," +
  25.             "name VARCHAR NOT NULL," + "age INTEGER NOT NULL," +
  26.             "height LONG NOT NULL," + "weight FLOAT NOT NULL," +
  27.             "married INTEGER NOT NULL," + "update_time VARCHAR NOT NULL" +
  28.             //演示数据库升级时要先把下面这行注释
  29.             ",phone VARCHAR" + ",password VARCHAR" + ");"
  30.         Log.d(TAG, "create_sql:" + create_sql)
  31.         db.execSQL(create_sql)
  32.     }
  33.     override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
  34.         Log.d(TAG, "onUpgrade oldVersion=$oldVersion, newVersion=$newVersion")
  35.         if (newVersion > 1) {
  36.             //Android的ALTER命令不支持一次添加多列,只能分多次添加
  37.             var alter_sql = "ALTER TABLE $TABLE_NAME ADD COLUMN phone VARCHAR;"
  38.             Log.d(TAG, "alter_sql:" + alter_sql)
  39.             db.execSQL(alter_sql)
  40.             alter_sql = "ALTER TABLE $TABLE_NAME ADD COLUMN password VARCHAR;"
  41.             Log.d(TAG, "alter_sql:" + alter_sql)
  42.             db.execSQL(alter_sql)
  43.         }
  44.     }
  45.     fun delete(condition: String): Int {
  46.         var count = 0
  47.         use {
  48.             count = delete(TABLE_NAME, condition, null)
  49.         }
  50.         return count
  51.     }
  52.     fun insert(info: UserInfo): Long {
  53.         val infoArray = mutableListOf(info)
  54.         return insert(infoArray)
  55.     }
  56.     fun insert(infoArray: MutableList<UserInfo>): Long {
  57.         var result: Long = -1
  58.         for (i in infoArray.indices) {
  59.             val info = infoArray[i]
  60.             var tempArray: List<UserInfo>
  61.             // 如果存在同名记录,则更新记录
  62.             // 注意条件语句的等号后面要用单引号括起来
  63.             if (info.name.isNotEmpty()) {
  64.                 val condition = "name='${info.name}'"
  65.                 tempArray = query(condition)
  66.                 if (tempArray.size > 0) {
  67.                     update(info, condition)
  68.                     result = tempArray[0].rowid
  69.                     continue
  70.                 }
  71.             }
  72.             // 如果存在同样的手机号码,则更新记录
  73.             if (info.phone.isNotEmpty()) {
  74.                 val condition = "phone='${info.phone}'"
  75.                 tempArray = query(condition)
  76.                 if (tempArray.size > 0) {
  77.                     update(info, condition)
  78.                     result = tempArray[0].rowid
  79.                     continue
  80.                 }
  81.             }
  82.             // 不存在唯一性重复的记录,则插入新记录
  83.             val cv = ContentValues()
  84.             cv.put("name", info.name)
  85.             cv.put("age", info.age)
  86.             cv.put("height", info.height)
  87.             cv.put("weight", info.weight)
  88.             cv.put("married", info.married)
  89.             cv.put("update_time", info.update_time)
  90.             cv.put("phone", info.phone)
  91.             cv.put("password", info.password)
  92.             use {
  93.                 result = insert(TABLE_NAME, "", cv)
  94.             }
  95.             // 添加成功后返回行号,失败后返回-1
  96.             if (result == -1L) {
  97.                 return result
  98.             }
  99.         }
  100.         return result
  101.     }
  102.     @JvmOverloads
  103.     fun update(info: UserInfo, condition: String = "rowid=${info.rowid}"): Int {
  104.         val cv = ContentValues()
  105.         cv.put("name", info.name)
  106.         cv.put("age", info.age)
  107.         cv.put("height", info.height)
  108.         cv.put("weight", info.weight)
  109.         cv.put("married", info.married)
  110.         cv.put("update_time", info.update_time)
  111.         cv.put("phone", info.phone)
  112.         cv.put("password", info.password)
  113.         var count = 0
  114.         use {
  115.             count = update(TABLE_NAME, cv, condition, null)
  116.         }
  117.         return count
  118.     }
  119.     fun query(condition: String): List<UserInfo> {
  120.         val sql = "select rowid,_id,name,age,height,weight,married,update_time,phone,password from $TABLE_NAME where $condition;"
  121.         Log.d(TAG, "query sql: " + sql)
  122.         var infoArray = mutableListOf<UserInfo>()
  123.         use {
  124.             val cursor = rawQuery(sql, null)
  125.             if (cursor.moveToFirst()) {
  126.                 while (true) {
  127.                     val info = UserInfo()
  128.                     info.rowid = cursor.getLong(0)
  129.                     info.xuhao = cursor.getInt(1)
  130.                     info.name = cursor.getString(2)
  131.                     info.age = cursor.getInt(3)
  132.                     info.height = cursor.getLong(4)
  133.                     info.weight = cursor.getFloat(5)
  134.                     //SQLite没有布尔型,用0表示false,用1表示true
  135.                     info.married = if (cursor.getInt(6) == 0) false else true
  136.                     info.update_time = cursor.getString(7)
  137.                     info.phone = cursor.getString(8)
  138.                     info.password = cursor.getString(9)
  139.                     infoArray.add(info)
  140.                     if (cursor.isLast) {
  141.                         break
  142.                     }
  143.                     cursor.moveToNext()
  144.                 }
  145.             }
  146.             cursor.close()
  147.         }
  148.         return infoArray
  149.     }
  150.     fun queryByPhone(phone: String): UserInfo {
  151.         val infoArray = query("phone='$phone'")
  152.         val info: UserInfo = if (infoArray.size>0) infoArray[0] else UserInfo()
  153.         return info
  154.     }
  155.     fun deleteAll(): Int = delete("1=1")
  156.     fun queryAll(): List<UserInfo> = query("1=1")
  157. }

因为ManagedSQLiteOpenHelper来自于Anko库,所以记得在UserDBHelper文件头部加上下面一行导入语句:

import org.jetbrains.anko.db.ManagedSQLiteOpenHelper

另外,有别于常见的anko-common包,Anko库把跟数据库有关的部分放到了anko-sqlite包中,故而还需修改模块的build.gradle文件,在dependencies节点中补充下述的anko-sqlite包编译配置:

    compile "org.jetbrains.anko:anko-sqlite:$anko_version"

现在有了用户信息表的管理类,在Activity代码中存取用户信息就方便多了,下面是往数据库存储用户信息和从数据库读取用户信息的代码片段:

  1.     var helper: UserDBHelper = UserDBHelper.getInstance(this)
  2.     //往数据库存储用户信息
  3.     btn_save.setOnClickListener {
  4.         when (true) {
  5.             et_name.text.isEmpty() -> toast("请先填写姓名")
  6.             et_age.text.isEmpty() -> toast("请先填写年龄")
  7.             et_height.text.isEmpty() -> toast("请先填写身高")
  8.             et_weight.text.isEmpty() -> toast("请先填写体重")
  9.             else -> {
  10.                 val info = UserInfo(name = et_name.text.toString(),
  11.                 age = et_age.text.toString().toInt(),
  12.                 height = et_height.text.toString().toLong(),
  13.                 weight = et_weight.text.toString().toFloat(),
  14.                 married = bMarried,
  15.                 update_time = DateUtil.nowDateTime)
  16.                 helper.insert(info)
  17.                 toast("数据已写入SQLite数据库")
  18.             }
  19.         }
  20.     }
  21.     
  22.     //从数据库读取用户信息
  23.     private fun readSQLite() {
  24.         val userArray = helper.queryAll()
  25.         var desc = "数据库查询到${userArray.size}条记录,详情如下:"
  26.         for (i in userArray.indices) {
  27.             val item = userArray[i]
  28.             desc = "$desc\n第${i+1}条记录信息如下:" +
  29.                     "\n 姓名为${item.name}" +
  30.                     "\n 年龄为${item.age}" +
  31.                     "\n 身高为${item.height}" +
  32.                     "\n 体重为${item.weight}" +
  33.                     "\n 婚否为${item.married}" +
  34.                     "\n 更新时间为${item.update_time}"
  35.         }
  36.         if (userArray.isEmpty()) {
  37.             desc = "数据库查询到的记录为空"
  38.         }
  39.         tv_sqlite.text = desc
  40.     }

点此查看Kotlin入门教程的完整目录


__________________________________________________________________________
打开微信扫一扫下面的二维码,或者直接搜索公众号“老欧说安卓”添加关注,更快更方便地阅读技术干货。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/1009193
推荐阅读
相关标签
  

闽ICP备14008679号