package com.example.mycalculation.data
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
class UserDatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
companion object {
private const val DATABASE_NAME = "UserDatabase.db"
private const val DATABASE_VERSION = 1
private const val TABLE_USERS = "users"
private const val COLUMN_ID = "id"
private const val COLUMN_USERNAME = "username"
private const val COLUMN_PASSWORD = "password"
}
override fun onCreate(db: SQLiteDatabase) {
val createTableQuery = ("CREATE TABLE " + TABLE_USERS + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_USERNAME + " TEXT UNIQUE,"
+ COLUMN_PASSWORD + " TEXT" + ")")
db.execSQL(createTableQuery)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("DROP TABLE IF EXISTS $TABLE_USERS")
onCreate(db)
}
/**
* 添加新用户
* @return 如果插入成功返回 true,如果用户名已存在返回 false
*/
fun addUser(username: String, password: String): Boolean {
val db = this.writableDatabase
val contentValues = ContentValues()
contentValues.put(COLUMN_USERNAME, username)
contentValues.put(COLUMN_PASSWORD, password)
val result = db.insert(TABLE_USERS, null, contentValues)
db.close()
return result != –1L
}
/**
* 验证用户登录
*/
fun checkUser(username: String, password: String): Boolean {
val db = this.readableDatabase
val columns = arrayOf(COLUMN_ID)
val selection = "$COLUMN_USERNAME = ? AND $COLUMN_PASSWORD = ?"
val selectionArgs = arrayOf(username, password)
val cursor = db.query(
TABLE_USERS,
columns,
selection,
selectionArgs,
null,
null,
null
)
val count = cursor.count
cursor.close()
db.close()
return count > 0
}
/**
* 检查用户名是否已存在
*/
fun isUsernameExists(username: String): Boolean {
val db = this.readableDatabase
val columns = arrayOf(COLUMN_ID)
val selection = "$COLUMN_USERNAME = ?"
val selectionArgs = arrayOf(username)
val cursor = db.query(
TABLE_USERS,
columns,
selection,
selectionArgs,
null,
null,
null
)
val count = cursor.count
cursor.close()
db.close()
return count > 0
}
}
这是一个用户注册和登录数据库,用Android内置的SQLite
1️⃣ 包声明
package com.example.mycalculation.data
- 作用:定义这个 Kotlin 文件的包(package),类似于文件夹,用来组织代码。
- Kotlin 中的包可以帮助你区分同名类,避免冲突。
- 比如这里 com.example.mycalculation.data 表示这是项目 mycalculation 下 data 相关的类。
2️⃣ 导入库
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
-
ContentValues
- 用于存放要插入数据库的键值对数据,比如 "username" -> "Tom"。
-
Context
- Android 中非常重要的类,表示当前应用环境,通常用来访问数据库、文件、资源等。
-
SQLiteDatabase
- 表示 SQLite 数据库对象,你可以通过它执行 SQL 语句(增删改查)。
-
SQLiteOpenHelper
- 是一个帮助类,用来管理 SQLite 数据库的创建和版本升级。
- 它会帮你自动调用 onCreate 和 onUpgrade。
3️⃣ 类声明
class UserDatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION)
-
class UserDatabaseHelper(context: Context)
- 声明了一个类 UserDatabaseHelper,构造函数接收一个 Context。
-
: SQLiteOpenHelper(…)
- 表示继承 SQLiteOpenHelper,也就是让这个类拥有 SQLite 管理能力。
-
context → 当前应用环境
-
DATABASE_NAME → 数据库文件名
-
null → 默认的 CursorFactory,一般不用改
-
DATABASE_VERSION → 数据库版本号,用于升级管理
总结:这行代码的意思是,我们创建一个名叫 UserDatabaseHelper 的类,它能管理数据库创建、升级等。
4️⃣ companion object(伴生对象)
companion object {
private const val DATABASE_NAME = "UserDatabase.db"
private const val DATABASE_VERSION = 1
private const val TABLE_USERS = "users"
private const val COLUMN_ID = "id"
private const val COLUMN_USERNAME = "username"
private const val COLUMN_PASSWORD = "password"
}
-
Kotlin 特有写法 companion object
- 相当于 Java 中的 static,类级别变量/方法。
- 在整个类中可以直接访问,不需要实例化对象。
-
const val
- 常量,编译时确定,不会改变。
-
作用:这里定义数据库相关信息和字段名,方便后续使用。
5️⃣ onCreate 方法
override fun onCreate(db: SQLiteDatabase) {
val createTableQuery = ("CREATE TABLE " + TABLE_USERS + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_USERNAME + " TEXT UNIQUE,"
+ COLUMN_PASSWORD + " TEXT" + ")")
db.execSQL(createTableQuery)
}
-
override
- 表示重写父类 SQLiteOpenHelper 的方法。
-
onCreate(db: SQLiteDatabase)
- 当数据库第一次被创建时调用。
- 参数 db 是 SQLiteDatabase 对象,用它来执行 SQL 语句。
-
val createTableQuery = …
-
拼接 SQL 创建表语句:
CREATE TABLE users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
password TEXT
)- id → 自增主键
- username → 文本类型,唯一约束
- password → 文本类型
-
-
db.execSQL(createTableQuery)
- 执行 SQL 语句,创建表。
💡 小知识:
-
Kotlin 字符串拼接:"Hello " + name 或使用 模板字符串更推荐:
val createTableQuery = "CREATE TABLE $TABLE_USERS (" +
"$COLUMN_ID INTEGER PRIMARY KEY AUTOINCREMENT," +
"$COLUMN_USERNAME TEXT UNIQUE," +
"$COLUMN_PASSWORD TEXT)"
⑥ onUpgrade 方法
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("DROP TABLE IF EXISTS $TABLE_USERS")
onCreate(db)
}
作用
-
当数据库版本号 (DATABASE_VERSION) 升高 时,这个方法会被自动调用。
-
参数:
- db → 数据库对象
- oldVersion → 旧的版本号
- newVersion → 新的版本号
方法内部逻辑
db.execSQL("DROP TABLE IF EXISTS $TABLE_USERS")
- 执行 SQL 语句删除表 users(如果存在的话)。
- $TABLE_USERS 是 Kotlin 字符串模板,等价于 "users"。
- 目的是保证升级时重新创建表,避免表结构冲突。
onCreate(db)
- 删除表后重新调用 onCreate 创建新表。
- 保证数据库表结构是最新的。
💡 注意:
- 这种做法适合 开发阶段或数据不重要 的情况。
- 真正上线项目时,通常要写迁移逻辑而不是直接删表,否则用户数据会丢失。
⑦ addUser 方法
fun addUser(username: String, password: String): Boolean {
val db = this.writableDatabase
val contentValues = ContentValues()
contentValues.put(COLUMN_USERNAME, username)
contentValues.put(COLUMN_PASSWORD, password)
val result = db.insert(TABLE_USERS, null, contentValues)
db.close()
return result != –1L
}
作用
- 用于向 users 表插入一条新用户数据。
- 返回 true → 插入成功
- 返回 false → 插入失败(例如用户名已存在)
详细拆解
val db = this.writableDatabase
- this → 当前的 UserDatabaseHelper 对象
- writableDatabase → 获取 可写数据库(如果数据库不存在会自动创建)
- 后续所有操作都基于 db 对象进行
val contentValues = ContentValues()
contentValues.put(COLUMN_USERNAME, username)
contentValues.put(COLUMN_PASSWORD, password)
-
ContentValues 是 Android 提供的容器,用于存储 键值对(列名 → 数据)
-
.put() 方法可以放入不同类型数据(字符串、整数、布尔等)
-
最终数据长这样:
{
"username": "Tom",
"password": "123456"
}
val result = db.insert(TABLE_USERS, null, contentValues)
-
insert(tableName, nullColumnHack, values)
- tableName → 表名
- nullColumnHack → 当 values 为空时指定列名(这里不需要,用 null)
- values → 要插入的数据
-
返回值:
- 如果成功 → 返回新插入行的 ID(Long 类型)
- 如果失败 → 返回 -1
- 因此 return result != -1L 就能判断是否成功
db.close()
- 操作完数据库一定要关闭,避免内存泄漏和锁表问题。
Kotlin 语法亮点
- fun addUser(…) : Boolean → 定义函数并指定返回类型
- 字符串模板 $COLUMN_USERNAME、$TABLE_USERS → 比拼接字符串更方便
- result != -1L → Kotlin 的布尔表达式直接返回
⑧ 使用示例
val dbHelper = UserDatabaseHelper(context)
// 尝试添加用户
val isAdded = dbHelper.addUser("Tom", "123456")
if (isAdded) {
println("用户添加成功")
} else {
println("用户名已存在")
}
- 会自动检查用户名是否重复(因为 username 列是 UNIQUE)
- 如果重复 → insert 返回 -1 → 返回 false
⑨ checkUser 方法
fun checkUser(username: String, password: String): Boolean {
val db = this.readableDatabase
val columns = arrayOf(COLUMN_ID)
val selection = "$COLUMN_USERNAME = ? AND $COLUMN_PASSWORD = ?"
val selectionArgs = arrayOf(username, password)
val cursor = db.query(
TABLE_USERS,
columns,
selection,
selectionArgs,
null,
null,
null
)
val count = cursor.count
cursor.close()
db.close()
return count > 0
}
功能
- 检查数据库中是否有 用户名 + 密码 匹配的用户
- 用于 登录验证
详细拆解
1️⃣ 获取可读数据库
val db = this.readableDatabase
- 与 writableDatabase 不同,readableDatabase 是只读的
- 查询数据用它就够了,效率更高
2️⃣ 指定查询的列
val columns = arrayOf(COLUMN_ID)
- 查询列,这里只查 id 就够了,不需要拿出所有数据(密码、用户名)
- 提高效率
3️⃣ 构造查询条件
val selection = "$COLUMN_USERNAME = ? AND $COLUMN_PASSWORD = ?"
val selectionArgs = arrayOf(username, password)
- selection → SQL WHERE 子句,? 是占位符
- selectionArgs → 占位符对应的实际值
- SQL 实例:
SELECT id FROM users WHERE username = 'Tom' AND password = '123456';
- 使用占位符可以防止 SQL 注入攻击
4️⃣ 执行查询
val cursor = db.query(
TABLE_USERS,
columns,
selection,
selectionArgs,
null,
null,
null
)
-
query 方法参数:
- table → 表名
- columns → 查询列
- selection → 条件
- selectionArgs → 条件值
- groupBy → 分组(这里不用,填 null)
- having → 分组条件(不用,null)
- orderBy → 排序(不用,null)
-
返回 Cursor 对象,可以遍历查询结果
5️⃣ 获取结果
val count = cursor.count
- cursor.count → 查询到的行数
- 如果大于 0,说明有匹配用户
6️⃣ 关闭资源
cursor.close()
db.close()
- Cursor 和数据库 都要关闭,避免内存泄漏和锁表问题
7️⃣ 返回结果
return count > 0
- 如果匹配行数 > 0 → 返回 true
- 否则 → 返回 false
⑩ isUsernameExists 方法
fun isUsernameExists(username: String): Boolean {
val db = this.readableDatabase
val columns = arrayOf(COLUMN_ID)
val selection = "$COLUMN_USERNAME = ?"
val selectionArgs = arrayOf(username)
val cursor = db.query(
TABLE_USERS,
columns,
selection,
selectionArgs,
null,
null,
null
)
val count = cursor.count
cursor.close()
db.close()
return count > 0
}
功能
- 检查用户名是否已存在
- 用于注册时避免重复用户名
与 checkUser 的区别
查询条件不同:
"$COLUMN_USERNAME = ?"
- 只匹配用户名,不需要密码
用法场景不同:
- checkUser → 登录验证
- isUsernameExists → 注册前检查重复
使用示例
val dbHelper = UserDatabaseHelper(context)
// 登录验证
val canLogin = dbHelper.checkUser("Tom", "123456")
if (canLogin) println("登录成功") else println("用户名或密码错误")
// 注册验证
val exists = dbHelper.isUsernameExists("Tom")
if (exists) println("用户名已存在") else println("可以注册")
11 Kotlin 亮点总结
字符串模板
"$COLUMN_USERNAME = ?"
数组字面量
val columns = arrayOf(COLUMN_ID)
val selectionArgs = arrayOf(username, password)
简洁的布尔返回
return count > 0
💡 小技巧:
- 可以把 checkUser 改成只查询一行,效率更高:
cursor.moveToFirst()
return cursor.count > 0
- 对于用户表小数据量,差别不大,但大型表建议优化。


