我需要获取'id'值,每当我使用以下函数在数据库中添加新行时,该值会自动生成。
TaskItem.kt
@Entity(tableName = "task_item_table")
class TaskItem(
// Date Info
@ColumnInfo(name = "hour") var hour: Int, // Hours
@ColumnInfo(name = "minutes") var minutes: Int, // Minutes
@ColumnInfo(name = "totalMinutes") var totalMinutes: Int, // HoursId (total of minutes, for sorting)
// Sound Info
@ColumnInfo(name = "withMusic") var withMusic: Boolean, // With Music at the end
@ColumnInfo(name = "isActive") var isActive: Boolean, // If it will ring
// Sound Volume
// @ColumnInfo(name = "volume") var volume: Int, // If it will ring
@PrimaryKey(autoGenerate = true) var id: Int = 0
)
字符串
正如你所看到的,主键总是有一个唯一的整数。
TaskItemDao.kt
@Dao
interface TaskItemDao
{
@Query("SELECT * FROM task_item_table ORDER BY id ASC")
fun allTaskItems(): Flow<MutableList<TaskItem>>
@Query("UPDATE task_item_table SET isActive=:newActiveValue WHERE isActive=:isActive")
suspend fun setAllAlarmsTaskItem(isActive: Boolean, newActiveValue: Boolean)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTaskItem(taskItem: TaskItem)
@Update
suspend fun updateTaskItem(taskItem: TaskItem)
@Delete
suspend fun deleteTaskItem(taskItem: TaskItem)
}
型
TaskItemRepository.kt
class TaskItemRepository(private val taskItemDao: TaskItemDao)
{
val allTaskItems: Flow<MutableList<TaskItem>> = taskItemDao.allTaskItems()
@WorkerThread
suspend fun insertTaskItem(taskItem: TaskItem)
{
taskItemDao.insertTaskItem(taskItem)
}
@WorkerThread
suspend fun updateTaskItem(taskItem: TaskItem)
{
taskItemDao.updateTaskItem(taskItem)
}
@WorkerThread
suspend fun deleteTaskItem(taskItem: TaskItem)
{
taskItemDao.deleteTaskItem(taskItem)
}
@WorkerThread
suspend fun setAllAlarmsTaskItem(isActive: Boolean, newActiveValue: Boolean)
{
taskItemDao.setAllAlarmsTaskItem(isActive, newActiveValue)
}
}
型
TaskViewModel.kt
class TaskViewModel(private val repository: TaskItemRepository): ViewModel()
{
val taskItems: LiveData<MutableList<TaskItem>> = repository.allTaskItems.asLiveData()
private lateinit var taskViewModel: TaskViewModel
fun addTaskItem(taskItem: TaskItem) = viewModelScope.launch {
repository.insertTaskItem(taskItem)
}
fun updateTaskItem(taskItem: TaskItem) = viewModelScope.launch {
repository.updateTaskItem(taskItem)
}
fun deleteTaskItem(taskItem: TaskItem) = viewModelScope.launch {
repository.deleteTaskItem(taskItem)
}
fun setAllAlarmsTaskItem(isActive: Boolean, newActiveValue: Boolean) = viewModelScope.launch {
repository.setAllAlarmsTaskItem(isActive, newActiveValue)
}
fun setCompleted(taskItem: TaskItem) = viewModelScope.launch {
repository.updateTaskItem(taskItem)
}
}
class TaskItemModelFactory(private val repository: TaskItemRepository) : ViewModelProvider.Factory
{
override fun <T : ViewModel> create(modelClass: Class<T>): T
{
if (modelClass.isAssignableFrom(TaskViewModel::class.java))
return TaskViewModel(repository) as T
throw IllegalArgumentException("Unknown ViewModel class")
}
}
型
NewTaskSheet.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val activity = requireActivity()
binding.tvGuardar.setOnClickListener {
saveAction()
}
}
private fun saveAction(){
// ... some more code
if (taskItem == null)
{
val newTask = TaskItem(hour, minutes, totalMinutes, withMusic, isActive)
taskViewModel.addTaskItem(newTask)
// Here is where i need to get the id value, so i can passed to my alarm service
}
// ... some more code
alarmService.setRepetitiveAlarm(timeInMilis, musicHour, musicMinutes, withMusic)
}
型
我试过使用以下函数,但没有成功:所以基本上我只是在每个函数中返回。
TaskViewModel.kt
这是我认为导致问题的函数,因为它使程序崩溃:
fun addTaskItem(taskItem: TaskItem): Long {
// return@async repository.insertTaskItem(taskItem)
return runBlocking(viewModelScope.coroutineContext) {
return@runBlocking repository.insertTaskItem(taskItem)
}
}
// Also tried with this function.
// This one didn't crashed it just return some sort of string that
// didn't contained the id that I was looking for
fun addTaskItem(taskItem: TaskItem): Deferred<Long> = viewModelScope.async {
return@async repository.insertTaskItem(taskItem)
}
型
TaskItemRepository.kt
@WorkerThread
suspend fun insertTaskItem(taskItem: TaskItem): Long
{
return taskItemDao.insertTaskItem(taskItem)
}
型
TaskItemDao.kt
我读到,通过返回Long,它会自动返回主键的值。
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTaskItem(taskItem: TaskItem): Long
型
我希望能够有'id'值(primarykey),它被赋予了相应的创建行,这样我就可以使用它作为我的pendingIntents的requestCode。
private fun getPendingIntent(intent: Intent) =
PendingIntent.getBroadcast(
context,
0, // Here is where the id should be
intent,
//PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE
PendingIntent.FLAG_UPDATE_CURRENT
)
型
或者有没有另一种正确处理“请求代码”的策略?
我的应用程序是一个闹钟,所以每个闹钟都必须有一个唯一的代码,将被保存在数据库中,以便以后能够删除创建的闹钟。
2条答案
按热度按时间2hh7jdfx1#
在TaskItemDao中,从插入返回ID
字符串
在TaskItemRepository中,再次返回ID
型
在TaskViewModel中,你可以添加项目,获取ID,然后返回它。注意,要从协程作用域返回,你必须将函数标记为suspend,并使用调用者上下文。这强制要求从协程作用域调用函数。
型
注意
Dispatchers.IO
,当你对一个DAO方法进行Room调用时,你总是想指定它,而这个DAO方法不返回Flow。你看到的崩溃很可能是因为在主线程上使用了Room,这是不允许的(IO也会阻止)。在UI层,您可以使用Fragment的生命周期范围调用新的ViewModel函数
型
需要newTaskID的代码将进入协程作用域。
我建议阅读关于Coroutines的文章,并查看additional resources。在使用Room时,对apec概念有很强的理解是很重要的。
afdcj2ne2#
在
viewmodelScope
中调用你的仓库方法insertTaskItem
,并将返回的id保存到liveData或stateFlow中,然后你就可以从你的视图中观察liveData了。这就是我从问题中理解的,如果你不需要视图中的id,那么就在viewModel中处理它字符串
注意,你不需要使用
withContext
来将线程更改为IO,因为Room会自动处理这个问题,并且所有的dao suspend函数都可以安全地从主线程调用。