我对Android开发非常陌生.
我有一个房间结果数据库:
@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 }
}
}
}
}
有一个ASO
@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<Result>
@Query("SELECT * FROM results ORDER BY date ASC")
fun getAllResults() : Flow<List<Result>>
}
以及存储库
class ResultRepository(private val resultDao : ResultDao) {
fun getAllResults(): Flow<List<Result>> = resultDao.getAllResults()
suspend fun getResultsSmoothed(numSteps : Int) : List<Result> {
var allResults : List<Result> = 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<Result>()
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 <= nextDate && (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 <= LocalDateTime.parse(acc.date))) r
else acc
}
if (resultAfter == resultPrior) {
val newResult = Result(date = nextDate.toString(), result = resultPrior.result)
hundredResults = hundredResults + newResult
} else {
val resultPriorDate = LocalDateTime.parse(resultPrior.date)
val resultAfterDate = LocalDateTime.parse(resultAfter.date)
val periodBetween = Duration.between(resultPriorDate, resultAfterDate)
val periodOver = Duration.between(resultPriorDate, nextDate)
val percentageOver =
periodOver.seconds.toDouble() / periodBetween.seconds.toDouble();
val resultDifference = resultAfter.result - resultPrior.result;
val increaseToPriorAmount = resultDifference.toDouble() * percentageOver;
val stepResult = resultPrior.result + increaseToPriorAmount;
val newResult = Result(date = nextDate.toString(), result = stepResult.toFloat())
hundredResults = hundredResults + newResult
}
nextDate = nextDate.plusSeconds(step)
}
return hundredResults
}
suspend fun getResultLabels(numLabels : Int) : List<String> {
var allResults : List<Result> = 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)
val step = period.seconds / numLabels
var dateLabels = listOf<String>()
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
正在处理数据库中的一些值并返回内容.我将其放在这里的原因是将其提供给视图模型,因为我已经明白我不应该在我的组合中进行这种处理.
然后我的视图模型
class ResultViewModel(private val repository: ResultRepository) : ViewModel() {
val allResults = repository.getAllResults()
fun getSmoothedResults(num : Int) : Flow<List<Result>> {
return flow {
val results = repository.getResultsSmoothed(num)
Log.d("ME vm", results.toString())
emit(results)
}
}
fun getResultLabels(num : Int) : Flow<List<String>> {
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 <T : ViewModel> create(modelClass : Class<T>) : T {
if(modelClass.isAssignableFrom(ResultViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return ResultViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
我试图做的是将这些List
放入Flow
中,以便使用它们的组合将自动更新.
例如:
@Composable
fun Metrics(resultViewModel: ResultViewModel,
resultList : List<Result>?) {
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}")
}
}
}
}
}
}
然而,我的日志(log)呼叫有一个空列表.我可能完全错误地处理这个问题,但我不确定.我对协程和状态的使用以及它们如何相互作用有点困惑.