当我在 Android Studio 中使用 Room 搜索记录时,如何显示 Loading UI based different complex?
How can I display Loading UI based different complex when I search records using Room in Android Studio?
以下代码来自article.
使用wordRepository.allWords()
查询记录会花时间,所以作者先设置_isLoading.value = true
,然后查询记录,最后在fun load()
.set _isLoading.value = false
.
我觉得作者希望在查询比较复杂的时候,可以长时间显示LoadingUi()
但我认为这些代码存在一些问题。
suspend fun allWords(): Flow<PagingData<Word>>
是冷流,所以suspend fun allWords()
一下子return,_isLoading.value = false
就上线了在代码B中很快。我认为LoadingUi()
无论有3000条记录还是10条记录都会保持相同的时间。
解决方案有问题吗?我希望LoadingUi()
在查询需要处理3000条记录时保持长时间显示,而LoadingUi()
在查询需要处理10条记录时保持短时间显示。
代码A
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.load()
setContent {
...
val isLoading by viewModel.isLoading.collectAsState(false)
WordsTheme {
when {
isLoading -> LoadingUi()
else -> WordListUi(...)
}
}
}
}
}
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val _isLoading = MutableStateFlow(true)
val isLoading: StateFlow<Boolean> = _isLoading
fun load() = effect {
_isLoading.value = true
allWords.value = wordRepository.allWords()
_isLoading.value = false
}
private fun effect(block: suspend () -> Unit) {
viewModelScope.launch(Dispatchers.IO) { block() }
}
}
class WordRepository(...) {
suspend fun allWords(): Flow<PagingData<Word>> = wordStore.ensureIsNotEmpty().all()
suspend fun allWords(term: String): Flow<PagingData<Word>> = wordStore.ensureIsNotEmpty().all(term)
...
}
代码B
fun load() = effect {
_isLoading.value = true
//suspend fun allWords(): Flow<PagingData<Word>> is cold Flow,
//wordRepository.allWords() will return at once no matter there is 3000 records or 10 records
allWords.value = wordRepository.allWords()
_isLoading.value = false
}
新增内容:
第一个运行代码C:E/My:Return的持续时间:57
第二个运行代码C:E/My:Return的持续时间:1099
一个冷流在开始收集它们之前不会开始产生价值,所以我认为它会在 第一个 运行 和 第二个运行.
suspend fun allWords(): Flow<PagingData<Word>>
是冷流,我觉得一下子就return,为什么第一个运行[=69=的时间不一样]和第二个运行?
代码C(本人修改)
fun load() = effect {
_isLoading.value = true
val a = Calendar.getInstance().timeInMillis //I add
allWords.value = wordRepository.allWords()
val b = Calendar.getInstance().timeInMillis //I add
Log.e("My","Duration for Return: "+(b-a)) //I add
_isLoading.value = false
}
//I modify
suspend fun allWords(): Flow<PagingData<Word>> {
//delay(10) //The first run
delay(1000) //The second run
return wordStore.ensureIsNotEmpty().all()
}
//I modify
suspend fun allWords(term: String): Flow<PagingData<Word>> {
//delay(10) //The first run
delay(1000) //The second run
return wordStore.ensureIsNotEmpty().all(term)
}
private suspend fun WordStore.ensureIsNotEmpty() = apply {
if (isEmpty()) {
val words = wordSource.load()
save(words)
}
}
我没有发现此解决方案有任何问题。函数 allWords()
在 WordRepository
中定义如下:
suspend fun allWords(): Flow<PagingData<Word>> = wordStore.ensureIsNotEmpty().all()
private suspend fun WordStore.ensureIsNotEmpty() = apply {
if (isEmpty()) {
val words = wordSource.load()
save(words)
}
}
这里调用allWords()
函数时先执行ensureIsNotEmpty()
(由于网络调用可能需要一些时间-wordSource.load()
),然后.all()
函数return是 Flow
.
函数 wordSource.load()
使用 Dispatchers.IO
上下文发出网络请求并在 WordSource
中定义如下:
suspend fun load(): List<Word> = withContext(Dispatchers.IO) {
client.getRemoteWords()
.lineSequence()
.map { Word(it) }
.toList()
}
因此 wordRepository.allWords()
发出网络请求并且执行可能需要一些时间,因此 MainViewModel
中的函数 load()
似乎是正确的:
fun load() = effect {
_isLoading.value = true
allWords.value = wordRepository.allWords()
_isLoading.value = false
}
A cold stream does not start producing values until one starts to collect them.
这是正确的,但是在 Flow
被 returned 之前的 allWords()
函数中,延迟发生了:
suspend fun allWords(): Flow<PagingData<Word>> {
delay(1000) // delay before wordStore.ensureIsNotEmpty().all() function returns a Flow
return wordStore.ensureIsNotEmpty().all()
}
这就是为什么你有不同的执行时间。
您可能会感到困惑,因为 allWords()
的 return 类型是 Flow
,但函数本身不会创建流。
so I think it will spend the same time between The first run and The second run.
要做到这一点,allWords()
函数应该使用 flow
构建器自行生成 Flow
:
fun allWords(): Flow<PagingData<Word>> = flow {
delay(1000)
...
}
以下代码来自article.
使用wordRepository.allWords()
查询记录会花时间,所以作者先设置_isLoading.value = true
,然后查询记录,最后在fun load()
.set _isLoading.value = false
.
我觉得作者希望在查询比较复杂的时候,可以长时间显示LoadingUi()
但我认为这些代码存在一些问题。
suspend fun allWords(): Flow<PagingData<Word>>
是冷流,所以suspend fun allWords()
一下子return,_isLoading.value = false
就上线了在代码B中很快。我认为LoadingUi()
无论有3000条记录还是10条记录都会保持相同的时间。
解决方案有问题吗?我希望LoadingUi()
在查询需要处理3000条记录时保持长时间显示,而LoadingUi()
在查询需要处理10条记录时保持短时间显示。
代码A
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.load()
setContent {
...
val isLoading by viewModel.isLoading.collectAsState(false)
WordsTheme {
when {
isLoading -> LoadingUi()
else -> WordListUi(...)
}
}
}
}
}
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val _isLoading = MutableStateFlow(true)
val isLoading: StateFlow<Boolean> = _isLoading
fun load() = effect {
_isLoading.value = true
allWords.value = wordRepository.allWords()
_isLoading.value = false
}
private fun effect(block: suspend () -> Unit) {
viewModelScope.launch(Dispatchers.IO) { block() }
}
}
class WordRepository(...) {
suspend fun allWords(): Flow<PagingData<Word>> = wordStore.ensureIsNotEmpty().all()
suspend fun allWords(term: String): Flow<PagingData<Word>> = wordStore.ensureIsNotEmpty().all(term)
...
}
代码B
fun load() = effect {
_isLoading.value = true
//suspend fun allWords(): Flow<PagingData<Word>> is cold Flow,
//wordRepository.allWords() will return at once no matter there is 3000 records or 10 records
allWords.value = wordRepository.allWords()
_isLoading.value = false
}
新增内容:
第一个运行代码C:E/My:Return的持续时间:57
第二个运行代码C:E/My:Return的持续时间:1099
一个冷流在开始收集它们之前不会开始产生价值,所以我认为它会在 第一个 运行 和 第二个运行.
suspend fun allWords(): Flow<PagingData<Word>>
是冷流,我觉得一下子就return,为什么第一个运行[=69=的时间不一样]和第二个运行?
代码C(本人修改)
fun load() = effect {
_isLoading.value = true
val a = Calendar.getInstance().timeInMillis //I add
allWords.value = wordRepository.allWords()
val b = Calendar.getInstance().timeInMillis //I add
Log.e("My","Duration for Return: "+(b-a)) //I add
_isLoading.value = false
}
//I modify
suspend fun allWords(): Flow<PagingData<Word>> {
//delay(10) //The first run
delay(1000) //The second run
return wordStore.ensureIsNotEmpty().all()
}
//I modify
suspend fun allWords(term: String): Flow<PagingData<Word>> {
//delay(10) //The first run
delay(1000) //The second run
return wordStore.ensureIsNotEmpty().all(term)
}
private suspend fun WordStore.ensureIsNotEmpty() = apply {
if (isEmpty()) {
val words = wordSource.load()
save(words)
}
}
我没有发现此解决方案有任何问题。函数 allWords()
在 WordRepository
中定义如下:
suspend fun allWords(): Flow<PagingData<Word>> = wordStore.ensureIsNotEmpty().all()
private suspend fun WordStore.ensureIsNotEmpty() = apply {
if (isEmpty()) {
val words = wordSource.load()
save(words)
}
}
这里调用allWords()
函数时先执行ensureIsNotEmpty()
(由于网络调用可能需要一些时间-wordSource.load()
),然后.all()
函数return是 Flow
.
函数 wordSource.load()
使用 Dispatchers.IO
上下文发出网络请求并在 WordSource
中定义如下:
suspend fun load(): List<Word> = withContext(Dispatchers.IO) {
client.getRemoteWords()
.lineSequence()
.map { Word(it) }
.toList()
}
因此 wordRepository.allWords()
发出网络请求并且执行可能需要一些时间,因此 MainViewModel
中的函数 load()
似乎是正确的:
fun load() = effect {
_isLoading.value = true
allWords.value = wordRepository.allWords()
_isLoading.value = false
}
A cold stream does not start producing values until one starts to collect them.
这是正确的,但是在 Flow
被 returned 之前的 allWords()
函数中,延迟发生了:
suspend fun allWords(): Flow<PagingData<Word>> {
delay(1000) // delay before wordStore.ensureIsNotEmpty().all() function returns a Flow
return wordStore.ensureIsNotEmpty().all()
}
这就是为什么你有不同的执行时间。
您可能会感到困惑,因为 allWords()
的 return 类型是 Flow
,但函数本身不会创建流。
so I think it will spend the same time between The first run and The second run.
要做到这一点,allWords()
函数应该使用 flow
构建器自行生成 Flow
:
fun allWords(): Flow<PagingData<Word>> = flow {
delay(1000)
...
}