Android 下用kotlin写一个sqlite

复制代码
package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.getValue
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.material3.Surface
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue

import com.example.myapplication.printDatabase
import com.example.myapplication.ui.theme.MyApplicationTheme
import kotlinx.coroutines.delay
import kotlin.collections.addAll
import kotlin.text.clear

// 数据类,表示数据库中的一个项目
data class Item(val id: Int? = null, val name: String, val description: String)

// 数据库帮助类,用于管理数据库的创建、升级和数据操作
class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

    companion object {
        private const val DATABASE_NAME = "item_database" // 数据库名称
        private const val DATABASE_VERSION = 1 // 数据库版本
        private const val TABLE_NAME = "items" // 表名
        private const val COLUMN_ID = "id" // ID 列名
        private const val COLUMN_NAME = "name" // 名称列名
        private const val COLUMN_DESCRIPTION = "description" // 描述列名
    }
    // 创建数据库表
    override fun onCreate(db: SQLiteDatabase) {
        val createTableQuery = "CREATE TABLE $TABLE_NAME ($COLUMN_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COLUMN_NAME TEXT, $COLUMN_DESCRIPTION TEXT)"
        db.execSQL(createTableQuery)
    }
    // 升级数据库表
    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        val dropTableQuery = "DROP TABLE IF EXISTS $TABLE_NAME"
        db.execSQL(dropTableQuery)
        onCreate(db)
    }
    // 插入一个项目
    fun insertItem(item: Item) {
        val db = writableDatabase
        val values = ContentValues().apply {
            put(COLUMN_NAME, item.name)
            put(COLUMN_DESCRIPTION, item.description)
        }
        db.insert(TABLE_NAME, null, values)
        db.close()
    }
    // 获取所有项目
    fun getAllItems(): List<Item> {
        val db = readableDatabase
        val query = "SELECT * FROM $TABLE_NAME"
        val cursor = db.rawQuery(query, null)
        val items = mutableListOf<Item>()

        if (cursor.moveToFirst()) {
            do {
                val id = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID))
                val name = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME))
                val description = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_DESCRIPTION))
                items.add(Item(id, name, description))
            } while (cursor.moveToNext())
        }

        cursor.close()
        db.close()
        return items
    }
    // 删除一个项目
    fun deleteItem(itemId: Int) {
        val db = writableDatabase
        db.delete(TABLE_NAME, "$COLUMN_ID=?", arrayOf(itemId.toString()))
        db.close()
    }
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            MyApplicationTheme {
                /*
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ){
                    Surface(
                        color = MaterialTheme.colorScheme.primary,
                        modifier = Modifier.padding(vertical = 25.dp, horizontal = 8.dp)
                    ) {
                        MainScreen()
                    }
                }*/
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Surface(
                        color = MaterialTheme.colorScheme.primary,
                        modifier = Modifier.padding(innerPadding)
                    ) {
                        MainScreen()
                    }
                }
            }
        }
    }
}

@Composable
fun MainScreen() {
    val context = LocalContext.current
    val dbHelper = remember { DatabaseHelper(context) } // 记住数据库帮助类实例
    var itemName by remember { mutableStateOf("") } // 项目名称输入框的值
    var itemDescription by remember { mutableStateOf("") } // 项目描述输入框的值
    val items = remember { mutableStateListOf<Item>() } // 存储项目列表
    val showDatabaseContent = remember { mutableStateOf(false) } // 是否显示数据库内容的标志

    // 创建一个 MutableInteractionSource 来跟踪按钮的交互状态
    val interactionSource = remember { MutableInteractionSource() }

    // 获取按钮是否被按下的状态
    val isPressed by interactionSource.collectIsPressedAsState()

    // 根据按钮是否被按下,选择不同的颜色
    val buttonColor = if (isPressed) {
        Color(0xFF87CEEB) // 按下时的颜色 (更深的蓝色)
    } else {
        Color(0xFFADD8E6) // 默认颜色 (浅蓝色)
    }

    items.addAll(dbHelper.getAllItems()) // 初始化时从数据库加载数据

    Column(modifier = Modifier.padding(1.dp)) {
        // 项目名称输入框
        OutlinedTextField(
            value = itemName,
            onValueChange = { itemName = it },
            label = { Text("项目名称") },
            modifier = Modifier
                .fillMaxWidth()
                .padding(1.dp),
            colors = OutlinedTextFieldDefaults.colors(
                focusedTextColor = Color.Black, // 获得焦点时的文本颜色
                unfocusedTextColor = Color.Black, // 未获得焦点时的文本颜色
                focusedLabelColor = Color.Blue, // 获得焦点时的标签颜色
                unfocusedLabelColor = Color.Black, // 未获得焦点时的标签颜色
                cursorColor = Color.Black, // 光标颜色
                focusedBorderColor = Color.Blue, // 获得焦点时的边框颜色
                unfocusedBorderColor = Color.Gray, // 未获得焦点时的边框颜色
                //disabledBorderColor = Color.Gray, //禁用时的边框颜色
                //errorBorderColor = Color.Red, // 错误时的边框颜色
            )
        )
        // 项目描述输入框
        OutlinedTextField(
            value = itemDescription,
            onValueChange = { itemDescription = it },
            label = { Text("项目描述") },
            modifier = Modifier
                .fillMaxWidth()
                .padding(1.dp),
            colors = OutlinedTextFieldDefaults.colors(
                focusedTextColor = Color.Black, // 获得焦点时的文本颜色
                unfocusedTextColor = Color.Black, // 未获得焦点时的文本颜色
                focusedLabelColor = Color.Blue, // 获得焦点时的标签颜色
                unfocusedLabelColor = Color.Black, // 未获得焦点时的标签颜色
                cursorColor = Color.Black, // 光标颜色
                focusedBorderColor = Color.Blue, // 获得焦点时的边框颜色
                unfocusedBorderColor = Color.Gray, // 未获得焦点时的边框颜色
                //disabledBorderColor = Color.Gray, //禁用时的边框颜色
                //errorBorderColor = Color.Red, // 错误时的边框颜色
            )
        )
        // 添加项目按钮
        /*
        Button(
            onClick = {
                val newItem = Item(name = itemName, description = itemDescription)
                dbHelper.insertItem(newItem) // 插入新项目到数据库
                items.clear() // 清空列表
                items.addAll(dbHelper.getAllItems()) // 重新从数据库加载数据
                itemName = "" // 清空输入框
                itemDescription = "" // 清空输入框
            },
            colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFADD8E6)),
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("添加项目")
        }
         */
        Button(
            onClick = {
                val newItem = Item(name = itemName, description = itemDescription)
                dbHelper.insertItem(newItem) // 插入新项目到数据库
                items.clear() // 清空列表
                items.addAll(dbHelper.getAllItems()) // 重新从数据库加载数据
                itemName = "" // 清空输入框
                itemDescription = "" // 清空输入框
            },
            colors = ButtonDefaults.buttonColors(containerColor = buttonColor), // 使用动态的按钮颜色
            modifier = Modifier.fillMaxWidth(),
            interactionSource = interactionSource // 将 interactionSource 传递给 Button
        ) {
            Text("添加项目")
        }



        // 显示/隐藏数据库按钮
        Button(
            onClick = {
                showDatabaseContent.value = !showDatabaseContent.value // 切换显示/隐藏状态
            },
            colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFADD8E6)),
        ) {
            Text("显示/隐藏 数据库")
        }
        // 根据 showDatabaseContent 的值决定是否显示数据库内容
        if (showDatabaseContent.value) {
            DatabaseContentScreen(dbHelper) // 显示数据库内容
        }
        /*
        LazyColumn(modifier = Modifier.padding(16.dp)) {
            items(items) { item ->
                ItemRow(item = item)
            }
        }*/
    }
}

@Composable
fun ItemRow(item: Item) {
    Column(modifier = Modifier.padding(8.dp)) {
        Text(text = "Name: ${item.name}")
        Text(text = "Description: ${item.description}")
    }
}

// 数据库内容屏幕 Composable
@Composable
fun DatabaseContentScreen(dbHelper: DatabaseHelper) {
    // 使用 remember 记住从数据库获取的数据,并转换为可变列表
    val items = remember { dbHelper.getAllItems().toMutableList() }
    // 记住当前选中的项目,初始为 null
    var selectedItem by remember { mutableStateOf<Item?>(null) }
    // 创建一个 LazyListState,用于控制 LazyColumn 的滚动
    val lazyListState = rememberLazyListState()

    Column(modifier = Modifier.padding(16.dp)) {

        // 删除按钮
        Button(
            onClick = {
                selectedItem?.let {
                    dbHelper.deleteItem(it.id!!) // 从数据库删除
                    items.remove(it) // 从列表中移除
                    selectedItem = null // 清空选中项
                }
            },
            enabled = selectedItem != null, // 仅当有选中项时才启用
            colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFADD8E6)),
            //modifier = Modifier.padding(top = 8.dp)
        ) {
            Text("删除选中项")
        }
        // 表头
        Row(modifier = Modifier
            .fillMaxWidth()
            .background(Color.LightGray)) {
            TableCell(text = "ID", weight = 0.1f, isHeader = true) // ID 列
            TableCell(text = "名称", weight = 0.4f, isHeader = true) // 名称列
            TableCell(text = "描述", weight = 0.5f, isHeader = true) // 描述列
        }

        // 表格行
        LazyColumn (
            state = lazyListState, // 将 LazyListState 绑定到 LazyColumn
            //reverseLayout = true // 设置反向布局,让列表从底部开始显示
        ){
            items(items) { item ->
                val isSelected = selectedItem?.id == item.id // 判断当前行是否被选中
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .clickable { selectedItem = if (isSelected) null else item } // 点击行时切换选中状态
                        .background(if (isSelected) Color.Cyan else Color.Transparent) // 根据选中状态改变背景色
                ) {
                    TableCell(text = item.id?.toString() ?: "", weight = 0.1f) // ID
                    TableCell(text = item.name, weight = 0.4f) // 名称
                    TableCell(text = item.description, weight = 0.5f) // 描述
                }
            }
        }
        // 使用 LaunchedEffect 在 items 改变时滚动到最底部
        LaunchedEffect(items) {
            if (items.isNotEmpty()) {
                //lazyListState.scrollToItem(0) // 滚动到索引为 0 的项目,因为是反向布局,所以是最后一条数据
                //lazyListState.scrollToItem(items.size - 1) // 滚动到最后一条数据
                lazyListState.scrollToItem(items.lastIndex) // 滚动到最后一项
            }
        }

    }
}

@Composable
fun TableCell(text: String, weight: Float, isHeader: Boolean = false) {
    Text(
        text = text,
        modifier = Modifier
            .padding(8.dp),
        fontWeight = if (isHeader) FontWeight.Bold else FontWeight.Normal
    )
}

fun printDatabase(dbHelper: DatabaseHelper) {
    val items = dbHelper.getAllItems()
    Log.d("DatabaseContent", "--- Database Content ---")
    for (item in items) {
        Log.d("DatabaseContent", "ID: ${item.id}, Name: ${item.name}, Description: ${item.description}")
    }
    Log.d("DatabaseContent", "--- End of Database Content ---")
}
相关推荐
HLC++11 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼15 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
Ai_easygo15 小时前
MCP 协议实战:用 Claude Desktop 连本地 SQLite,5 分钟搭一个能查数据的 AI 助手
jvm·人工智能·sqlite
爱笑鱼15 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
btown16 小时前
Kotlin 版 MyBatis-Plus 查询优雅解决方案
kotlin
壮哥_icon16 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138418 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记18 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难18 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
小二·19 小时前
车载数字座舱实战:用魔珐星云打造下一代智能驾乘助手(附 Android/Kotlin 完整代码)
开发语言·kotlin