如果 kotlin 协程作业需要相当长的时间才能完成,如何有效地显示加载对话框?
How to efficiently show loading dialog if kotlin coroutine job takes quite some time to complete?
我想做的是使用kotlin协程进行数据库操作,同时给用户展示一个加载界面。我的基本实现如下:
fun loadSomeData(){
mainCoroutineScope.launch {
showLoadingDialog()
// suspening function over Dispatchers.IO, returns list
val dataList = fetchDataFromDatabase()
inflateDataIntoViews(dataList)
hideLoadingDialog()
}
}
当加载大型数据集需要相当长的时间时,这对我来说非常有用。但是在 fetchDataFromDatabase()
快速完成的情况下,快速连续显示和隐藏对话框会产生令人讨厌的故障效果。
所以我想要的是仅当 fetchDataFromDatabase()
函数花费超过 让我们说 ,100 毫秒才能完成时才显示对话框。
所以我的问题是,使用 kotlin 协程实现此目的的性能高效方法是什么?
这是一个想法:
fun loadSomeData(){
mainCoroutineScope.launch {
val dialogJob = launch {
delay(1000)
try {
showLoadingDialog()
coroutineContext.job.join()
} finally {
hideLoadingDialog()
}
}
val dataList = fetchDataFromDatabase()
inflateDataIntoViews(dataList)
dialogJob.cancel()
}
}
当您取消 dialogJob
时,它应该点击 delay
语句并阻止显示对话框,或者 join
语句,这将导致 finally
阻止执行并隐藏它。
加载对话框的主要目的是防止用户在加载时触摸UI,但不能保证这一点。在弹出对话框之前,用户总是有机会触摸某个按钮。
更好的方法是禁用或隐藏 UI 组件,或者通常显示 UI.
的 "loading version"
最好让用户取消加载而不是设置一个短的超时时间,所以你可能仍然需要一个显示取消按钮的对话框或小吃栏,或者你可以在你的应用程序中制作一个任务管理器页面,那将是虽然真的很复杂。
我是这样实现的,没有使用 !!
not null 运算符:
val deferred = lifecycleScope.async(Dispatchers.IO) {
// perform possibly long running async task here
}
lifecycleScope.launch (Dispatchers.Main){
// delay showing the progress dialog for whatever time you want
delay(100)
// check if the task is still active
if (deferred.isActive) {
// show loading dialog to user if the task is taking time
val progressDialogBuilder = createProgressDialog()
try {
progressDialogBuilder.show()
// suspend the coroutine till deferred finishes its task
// on completion, deferred result will be posted to the
// function and try block will be exited.
val result = deferred.await()
onDeferredResult(result)
} finally {
// when deferred finishes and exits try block finally
// will be invoked and we can cancel the progress dialog
progressDialogBuilder.cancel()
}
} else {
// if deferred completed already withing the wait time, skip
// showing the progress dialog and post the deferred result
val result = deferred.await()
onDeferredResult(result)
}
}
我想做的是使用kotlin协程进行数据库操作,同时给用户展示一个加载界面。我的基本实现如下:
fun loadSomeData(){
mainCoroutineScope.launch {
showLoadingDialog()
// suspening function over Dispatchers.IO, returns list
val dataList = fetchDataFromDatabase()
inflateDataIntoViews(dataList)
hideLoadingDialog()
}
}
当加载大型数据集需要相当长的时间时,这对我来说非常有用。但是在 fetchDataFromDatabase()
快速完成的情况下,快速连续显示和隐藏对话框会产生令人讨厌的故障效果。
所以我想要的是仅当 fetchDataFromDatabase()
函数花费超过 让我们说 ,100 毫秒才能完成时才显示对话框。
所以我的问题是,使用 kotlin 协程实现此目的的性能高效方法是什么?
这是一个想法:
fun loadSomeData(){
mainCoroutineScope.launch {
val dialogJob = launch {
delay(1000)
try {
showLoadingDialog()
coroutineContext.job.join()
} finally {
hideLoadingDialog()
}
}
val dataList = fetchDataFromDatabase()
inflateDataIntoViews(dataList)
dialogJob.cancel()
}
}
当您取消 dialogJob
时,它应该点击 delay
语句并阻止显示对话框,或者 join
语句,这将导致 finally
阻止执行并隐藏它。
加载对话框的主要目的是防止用户在加载时触摸UI,但不能保证这一点。在弹出对话框之前,用户总是有机会触摸某个按钮。
更好的方法是禁用或隐藏 UI 组件,或者通常显示 UI.
的 "loading version"最好让用户取消加载而不是设置一个短的超时时间,所以你可能仍然需要一个显示取消按钮的对话框或小吃栏,或者你可以在你的应用程序中制作一个任务管理器页面,那将是虽然真的很复杂。
我是这样实现的,没有使用 !!
not null 运算符:
val deferred = lifecycleScope.async(Dispatchers.IO) {
// perform possibly long running async task here
}
lifecycleScope.launch (Dispatchers.Main){
// delay showing the progress dialog for whatever time you want
delay(100)
// check if the task is still active
if (deferred.isActive) {
// show loading dialog to user if the task is taking time
val progressDialogBuilder = createProgressDialog()
try {
progressDialogBuilder.show()
// suspend the coroutine till deferred finishes its task
// on completion, deferred result will be posted to the
// function and try block will be exited.
val result = deferred.await()
onDeferredResult(result)
} finally {
// when deferred finishes and exits try block finally
// will be invoked and we can cancel the progress dialog
progressDialogBuilder.cancel()
}
} else {
// if deferred completed already withing the wait time, skip
// showing the progress dialog and post the deferred result
val result = deferred.await()
onDeferredResult(result)
}
}