20240215

为了便于开发和维护,一般来说应用应当有界面层和数据层,界面层用于在屏幕上显示应用数据,数据层包含应用的业务逻辑并公开应用数据。
界面层也由两部分,一部分呈现界面和数据,一部分处理数据和逻辑。简单的用我已知的知识理解,就是看得见的HTML CSS与看不见的JavaScript,虽然也常常用JavaScript产生看的见的效果。
而数据层类似之前写的后端,数据源当然也可以是其他网络上部署的东西,或者我这里使用的本地数据库。

比如说考虑数据从用户界面到本地的数据库应该是怎样的,以简易的记账本App为例

//App.kt
val inputName = viewModel.inputName  
val inputMoney = viewModel.inputMoney
TextField(  
	value = inputName.value,  
	onValueChange = { inputName.value = it },  
	label = { Text("Name") },  
)  
TextField(  
	value = inputMoney.value,  
	onValueChange = { inputMoney.value = it },  
	label = { Text("Money") },  
)  
Button(  
	onClick = { viewModel.submitData() },  
  
) {  
	Text("Submit")  
}

在呈现界面的地方有两个TextField来填写数据,每次值改变就会更新。inputName 来自viewModel。
在ViewModel中

//ViewModel.kt
private var db:AppDatabase = Room.databaseBuilder(  
	ExpenseTrackerApplication.context,  
	AppDatabase::class.java, "app-database"  
).allowMainThreadQueries().build()  
private var expenseRecordDao: ExpenseRecordDao = db.expenseRecordDao()

val inputName = mutableStateOf("")  
val inputMoney = mutableStateOf("")  
fun submitData() {  
	val expenseRecord = ExpenseRecord(0,inputName.value,"",inputMoney.value.toDouble(), Instant.now())  
	expenseRecordDao.insertAll(expenseRecord)  
}

这里的insertAll方法来自数据访问对象,使用这些方法,就能对应用的数据库抽象访问。这里实例化了数据库,为了性能不允许主线程访问,但是为了暂时方便可以.allowMainThreadQueries()

//Dao.kt
interface ExpenseRecordDao {  
@Insert  
fun insertAll(vararg record: ExpenseRecord)  
@Update  
fun updateRecords(vararg record: ExpenseRecord)  
@Delete  
fun delete(record: ExpenseRecord)  
@Query("SELECT * FROM expense_record ORDER BY uid DESC")  
fun getAll(): List<ExpenseRecord>  
}
//AppDatabase.kt
@Database(entities = [ExpenseRecord::class], version = 1)  
@TypeConverters(Converters::class)  
	abstract class AppDatabase : RoomDatabase(){  
	abstract fun expenseRecordDao(): ExpenseRecordDao  
}

这里使用了自定义的数据转换器,因为sqlite并不支持Instant类型存储的时间,需要将它转换为Long来存储。

//Converters.kt
class Converters {  
	@TypeConverter  
	fun instantToLong(value: Instant): Long {  
		return value.toEpochMilli()  
	}  
	@TypeConverter  
	fun longToInstant(value: Long): Instant {  
		return Instant.ofEpochMilli(value)  
	}  
}

用来存储的数据模型

//model.kt
@Entity(tableName = "expense_record")  
	data class ExpenseRecord (  
	@PrimaryKey(autoGenerate = true) val uid:Int,  
	var name: String,  
	val description: String,  
	val money: Double,  
	val time: Instant  
)

这样,当你按下Submit按钮的时候,数据就会进入数据库。

posted @ 2024-02-16 15:04  satou_matsuzaka  阅读(1)  评论(0编辑  收藏  举报

This is a Test

メイドノココロハ アヤツリドール