提问人:excing 提问时间:6/26/2022 最后编辑:excing 更新时间:6/26/2022 访问量:543
为什么“lifecycleScope.launch”中耗时的操作会阻塞 UI 线程?
Why do time-consuming operations in `lifecycleScope.launch` block the UI thread?
问:
我从数据库中读取页面列表并显示在 .它看起来像这样:RecyclerView
视图模型:
@HiltViewModel
class BookDetailViewModel @Inject internal constructor(
savedStateHandle: SavedStateHandle,
private val bookRepository: BookRepository,
private val chapterRepository: ChapterRepository,
) : ViewModel() {
private var currentResult: Flow<PagingData<Chapter>>? = null
val bookID: Long = savedStateHandle.get<Long>(BOOK_ID_SAVED_STATE_KEY)!!
val book = bookRepository.getBook(bookID)
suspend fun getChapters(): Flow<PagingData<Chapter>> {
val lastChapterID = book.first().lastChapterID
val newResult = chapterRepository
.getChapters(bookID, lastChapterID)
.cachedIn(viewModelScope)
currentResult = newResult
return newResult
}
companion object {
private const val BOOK_ID_SAVED_STATE_KEY = "bookID"
}
}
和 ChapterListFragment:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
...
...
load()
return binding.root
}
private fun load() {
// Make sure we cancel the previous job before creating a new one
queryJob?.cancel()
queryJob = lifecycleScope.launch {
viewModel.getChapters().collectLatest { result ->
binding.hasChapters = true
adapter.submitData(lifecycle, result)
}
}
}
但是,在打开时,有一小段滞后,显然是卡住了。ChapterListFragment
我认为这是由于方法中读取数据库的操作造成的,但是我是在协程中进行的,我不明白为什么仍然存在滞后。viewModel.getChapters
不显示关联的。ProgressBar
binding.hasChapters
如果我在方法中添加一个,那么将以两秒钟的延迟打开。Thread.sleep(2000)
getChapters
ChapterListFragment
所以我有两个问题:
1. 为什么会这样?
我最初的理解是执行的代码不会阻塞当前的 UI 线程,但现在看来情况并非如此。lifecycleScope.launch
2. 如何正确刷新我的列表?
编辑
我使用以下代码,然后打开变得顺畅:ChapterListFragment
private fun load() {
// Make sure we cancel the previous job before creating a new one
queryJob?.cancel()
queryJob = lifecycleScope.launch(Dispatchers.IO) {
Thread.sleep(300)
withContext(Dispatchers.Main) {
viewModel.getChapters().collectLatest { result ->
binding.hasChapters = true
adapter.submitData(lifecycle, result)
}
}
}
}
我先阻塞了IO线程300ms,这是打开IO线程所需的动画时间,所以不会阻塞UI线程,可以正常显示。然后在主线程(UI线程)中获取分页列表并刷新,没有滞后。Fragment
ProgressBar
但我觉得这样不好,我不应该主动阻塞300毫秒,然后去获取列表。
答:
0赞
Darshan
6/26/2022
#1
这里需要考虑一些事项。
- 最好只给 a 充气,这样它就会尽快充气。
View
onCreateView
- 在通货膨胀后做其他与视图相关的工作。
onViewCreated
- 您正在使用 which 不是必需的,因为它类似于用于在块内进行某些处理后返回某些内容。(这“可能”会导致延迟,但不确定)
withContext
async {...}.await
由于您正在使用必须处理生命周期的位置,因此您可以执行如下操作:Flow
// Follows the inflated view's lifecycle
viewLifecycleOwner.lifecycleScope.launch {
// repeatOnLifecycle is a suspend function
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.getChapters().collectLatest { result ->
binding.hasChapters = true
adapter.submitData(lifecycle, result)
}
}
}
评论
0赞
excing
6/28/2022
无法找到该方法。repeatOnLifecycle
0赞
Darshan
6/28/2022
添加依赖项。lifecycle-runtime-ktx
0赞
excing
6/28/2022
我导入了包,它现在可以工作了。但还是有滞后,不够流畅,结果和修改前一样。lifecycle-runtime-ktx
评论
load()
onViewCreated
withContext
onCreateView