Запрос Android Jetpack Compose Room в зависимости от FlowAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Запрос Android Jetpack Compose Room в зависимости от Flow

Сообщение Anonymous »

Я пытаюсь добиться следующего поведения в своем приложении TODO:
  • когда пользователь касается круга на верхней панели, выбирается дата и список задач должен измениться, чтобы отобразить задачи на эту дату.
  • когда пользователь касается флажка или проводит пальцем по экрану, чтобы удалить задачу, запускается событие для сохранения в БД, и пользовательский интерфейс должен отражать эти изменения
    li>
для пояснения см. рисунок ниже:
[img]https://i .stack.imgur.com/dpBkMm.jpg[/img]

Я пробовал использовать поток, который сопоставляет последнюю выбранную дату с запросом к базе данных задач на эту дату, внутри TaskViewModel:

Код: Выделить всё

package com.pochopsp.dailytasks.domain

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pochopsp.dailytasks.data.database.entity.Task
import com.pochopsp.dailytasks.data.database.dao.TaskDao
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.last
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.util.Date

class TaskViewModel(
private val taskDao: TaskDao
): ViewModel() {

private val _selectedDate = MutableStateFlow(Date())
private var selectedDate: StateFlow = _selectedDate.asStateFlow()

private val _readTasksState = MutableStateFlow(ReadTasksState())

@OptIn(ExperimentalCoroutinesApi::class)
private val _tasks = selectedDate.flatMapLatest {
latestSelectedDate -> taskDao.getTasksForDate(latestSelectedDate)
}

val readTasksState = combine(_readTasksState, _tasks){ readtaskstate, tasks ->

readtaskstate.copy(
tasksForSelectedDate = tasksToDtos(tasks)
)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), ReadTasksState())

private fun tasksToDtos (tasks: List): List {
return tasks.map { t -> TaskCardDto(t.id, t.title, t.icon, t.done) }.toList()
}

fun onEvent(event: TaskEvent){
when(event){
is TaskEvent.DeleteTask -> {
viewModelScope.launch {
taskDao.deleteById(event.id)
}
}
is TaskEvent.SetDone -> {
viewModelScope.launch {
taskDao.updateDoneById(event.done, event.id)
}
}
is TaskEvent.SetSelectedDate ->  {
_selectedDate.value = event.selectedDate
}
}
}
}
TaskEvent.DeleteTask, TaskEvent.SetDone и TaskEvent.SetSelectedDate, которые вы видите в TaskViewModel, запускаются пользователем ввод в пользовательский интерфейс.
Это моя MainActivity:

Код: Выделить всё

package com.pochopsp.dailytasks

import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.room.Room
import com.pochopsp.dailytasks.data.database.Database
import com.pochopsp.dailytasks.domain.TaskCardDto
import com.pochopsp.dailytasks.domain.ReadTasksState
import com.pochopsp.dailytasks.domain.TaskViewModel
import com.pochopsp.dailytasks.presentation.navigation.Destinations
import com.pochopsp.dailytasks.presentation.screen.MainScreen
import com.pochopsp.dailytasks.presentation.theme.DailyTasksTheme
import kotlinx.coroutines.flow.MutableStateFlow

class MainActivity : ComponentActivity() {

private val db by lazy {
Room.databaseBuilder(
applicationContext,
Database::class.java,
"tasks.db"
).fallbackToDestructiveMigration().build()
}

private val viewModel by viewModels(
factoryProducer = {
// needed because our viewmodel has a parameter (in this case the dao interface)
object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun  create(modelClass: Class): T {
return TaskViewModel(db.taskDao, db.dayDao) as T
}
}
}
)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DailyTasksTheme(darkTheme = false) {
val readTasksState by viewModel.readTasksState.collectAsState()

val navController = rememberNavController()

NavHost(
navController = navController,
startDestination = "main")
{
composable(Destinations.Main.route) { MainScreen(state = readTasksState, onEvent = viewModel::onEvent){ navController.navigate(it.route) } }
// Add more destinations similarly.
}
}
}
}
}
ReadTasksState.kt:

Код: Выделить всё

package com.pochopsp.dailytasks.domain

import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import java.util.Date

data class ReadTasksState(
val tasksForSelectedDate: List = emptyList()
)
Это похоже на запрос TaskDao.getTasksForDate(latestSelectedDate), который возвращает Flow, сам зависит от Flow , поскольку дата, которую он получает на входе, сохраняется с использованием StateFlow.
Это вроде работает, но я не думаю, что это лучший способ сделайте это (или даже правильный способ сделать это).
Можете ли вы дать мне какой-нибудь совет или предложить лучший подход?

Подробнее здесь: https://stackoverflow.com/questions/782 ... ng-on-flow
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»