Как мне создать поток из базы данных Room, а также предварительно обработать значения?Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как мне создать поток из базы данных Room, а также предварительно обработать значения?

Сообщение Anonymous »

Я новичок в разработке Android.
У меня есть база данных результатов Room:

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

@Entity(tableName = "results")
data class Result(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val result : Float,
val date : String
)

@Database(
entities = [Result::class],
version = 1,
exportSchema = false
)
abstract class ResultDatabase : RoomDatabase() {
abstract fun resultDao() : ResultDao

companion object {
@Volatile
private var Instance : ResultDatabase? = null

fun getDatabase(context : Context) : ResultDatabase {
return Instance ?: synchronized(this) {
Room.databaseBuilder(context, ResultDatabase::class.java, "result_database")
.fallbackToDestructiveMigration()
.build()
.also { Instance = it }
}
}
}
}
С помощью DAO

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

@Dao
interface ResultDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(result : Result)

@Update
suspend fun update(result : Result)

@Delete
suspend fun delete(result : Result)

@Query("SELECT * FROM results WHERE id = :id")
fun getResult(id : Int) : Flow

@Query("SELECT * FROM results ORDER BY date ASC")
fun getAllResults() : Flow
}
и репозиторий

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

class ResultRepository(private val resultDao : ResultDao) {

fun getAllResults(): Flow = resultDao.getAllResults()

suspend fun getResultsSmoothed(numSteps : Int) : List {

var allResults : List = listOf()
getAllResults().collect { result -> allResults = allResults + result }

val minDate = LocalDateTime.parse(allResults.first().date)
val maxDate = LocalDateTime.parse(allResults.last().date)

val period = Duration.between(minDate, maxDate)

var step = period.seconds / numSteps

var hundredResults = listOf()

var nextDate = minDate

for (i in 0..numSteps) {

val resultPrior = allResults.fold(allResults.first()) { acc: Result, r ->
val rd = LocalDateTime.parse(r.date)
if (rd  LocalDateTime.parse(acc.date))) r
else acc
}

val resultAfter = allResults.fold(allResults.last()) { acc: Result, r ->
val rd = LocalDateTime.parse(r.date)
if (rd > nextDate && (rd   allResults = allResults + result }

val minDate = LocalDateTime.parse(allResults.first().date)
val maxDate = LocalDateTime.parse(allResults.last().date)

val period = Duration.between(minDate, maxDate)

val step = period.seconds / numLabels

var dateLabels = listOf()

var nextDate = minDate

for (i in 0..numLabels) {
val formatter = DateTimeFormatter.ofPattern("d MMM yy")
dateLabels = dateLabels + nextDate.format(formatter)
nextDate = nextDate.plusSeconds(step)
}

return dateLabels
}

@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun insertResult(result : Result) {
resultDao.insert(result)
}

@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun updateResult(result : Result) {
resultDao.update(result)
}

@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun deleteResult(result : Result) {
resultDao.delete(result)
}
}
Две функции getResultLabels и getResultsSmoothed обрабатывают некоторые значения из базы данных и возвращают данные. Причина, по которой я поместил это здесь, заключалась в том, чтобы предоставить это модели представления, потому что я понял, что мне не следует выполнять эту обработку в своих составных объектах.
Затем моя ViewModel

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

class ResultViewModel(private val repository: ResultRepository) : ViewModel() {

val allResults = repository.getAllResults()

fun getSmoothedResults(num : Int) : Flow {
return flow {
val results = repository.getResultsSmoothed(num)
Log.d("ME vm", results.toString())
emit(results)
}
}

fun getResultLabels(num : Int) : Flow {
return flow { emit(repository.getResultLabels(num)) }
}

fun update(result : Result) = viewModelScope.launch {
repository.updateResult(result)
}

fun delete(result : Result) = viewModelScope.launch {
repository.deleteResult(result)
}

fun insert(result : Result) = viewModelScope.launch {
repository.insertResult(result)
}
}

class ResultViewModelFactory(private val repository: ResultRepository) : ViewModelProvider.Factory {
override fun   create(modelClass : Class) : T {
if(modelClass.isAssignableFrom(ResultViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return ResultViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
Я пытаюсь поместить эти списки в Flow, чтобы компоновочные элементы, которые их используют, автоматически обновлялись.Например:

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

@Composable
fun Metrics(resultViewModel: ResultViewModel,
resultList : List?) {

if(resultList.isNullOrEmpty())
return

var dateLabels = resultViewModel.getResultLabels(5).collectAsState(initial = listOf())

var hundredResults = resultViewModel.getSmoothedResults(100).collectAsState(
initial = listOf()
)

Log.d("memememe", hundredResults.value.toString())

Column()
{
LineChart(
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
.padding(top = 12.dp, end = 12.dp),
linesChartData = listOf(LineChartData(
lineDrawer = SolidLineDrawer(color = MaterialTheme.colorScheme.onBackground),
points = hundredResults.value.map {
LineChartData.Point(it.result, it.id.toString())
})),
animation = simpleChartAnimation(),
pointDrawer = com.github.tehras.charts.line.renderer.point.NoPointDrawer,
labels = dateLabels.value,
xAxisDrawer = SimpleXAxisDrawer(
axisLineThickness = 1.dp,
axisLineColor = MaterialTheme.colorScheme.onBackground,
labelTextColor = MaterialTheme.colorScheme.onBackground
),
yAxisDrawer = SimpleYAxisDrawer(
axisLineThickness = 1.dp,
axisLineColor = MaterialTheme.colorScheme.onBackground,
labelTextColor = MaterialTheme.colorScheme.onBackground
)
)
DataTable(
modifier = Modifier.fillMaxWidth(),
columns = listOf(
DataColumn(
width = TableColumnWidth.Fixed(60.dp)
) {
Text("")
},
DataColumn {
Text("Date")
},
DataColumn {
Text("Result")
}
)
) {
resultList.forEach { r ->
row {
cell {
IconButton(onClick = { resultViewModel.delete(r) }) {
Icon(Icons.TwoTone.Delete, "Delete result")
}
}
cell {
Text(
text = LocalDateTime.parse(r.date)
.format(DateTimeFormatter.ofPattern("dd MMM yyyy"))
)
}
cell {
Text("${r.result}")
}
}
}
}
}
}
Однако мой вызов журнала содержит пустой список. Возможно, я совершенно неправильно подхожу к этой проблеме, но я не уверен. Меня немного смущает использование сопрограмм и состояний, а также то, как они взаимодействуют.

Подробнее здесь: https://stackoverflow.com/questions/784 ... lues-prior
Ответить

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

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

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

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

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