经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Kotlin入门(26)数据库ManagedSQLiteOpenHelper
来源:cnblogs  作者:aqi00  时间:2018/10/20 15:25:41  对本文有异议

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

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

  1. import org.jetbrains.anko.db.ManagedSQLiteOpenHelper

 

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

  1. 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. private fun readSQLite() {
  23. val userArray = helper.queryAll()
  24. var desc = "数据库查询到${userArray.size}条记录,详情如下:"
  25. for (i in userArray.indices) {
  26. val item = userArray[i]
  27. desc = "$desc\n第${i+1}条记录信息如下:" +
  28. "\n 姓名为${item.name}" +
  29. "\n 年龄为${item.age}" +
  30. "\n 身高为${item.height}" +
  31. "\n 体重为${item.weight}" +
  32. "\n 婚否为${item.married}" +
  33. "\n 更新时间为${item.update_time}"
  34. }
  35. if (userArray.isEmpty()) {
  36. desc = "数据库查询到的记录为空"
  37. }
  38. tv_sqlite.text = desc
  39. }

  

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号