Ben*_*aci 12 multithreading android android-asynctask kotlin kotlin-coroutines
AsyncTask 的典型用途:我想在另一个线程中运行一个任务,在该任务完成后,我想在我的 UI 线程中执行一些操作,即隐藏进度条。
任务将开始,TextureView.SurfaceTextureListener.onSurfaceTextureAvailable完成后我想隐藏进度条。同步执行此操作不起作用,因为它会阻止构建 UI 的线程,使屏幕变黑,甚至不显示我之后想隐藏的进度条。
到目前为止,我使用这个:
inner class MyTask : AsyncTask<ProgressBar, Void, ProgressBar>() {
override fun doInBackground(vararg params: ProgressBar?) : ProgressBar {
// do async
return params[0]!!
}
override fun onPostExecute(result: ProgressBar?) {
super.onPostExecute(result)
result?.visibility = View.GONE
}
}
Run Code Online (Sandbox Code Playgroud)
但是这些课程非常丑陋,所以我想摆脱它们。我想用 kotlin 协程来做到这一点。我尝试了一些变体,但它们似乎都不起作用。我最有可能怀疑的工作是这样的:
runBlocking {
// do async
}
progressBar.visibility = View.GONE
Run Code Online (Sandbox Code Playgroud)
但这不能正常工作。据我了解,它runBlocking不会像那样启动一个新线程AsyncTask,这正是我需要它做的。但是使用thread协程,我没有看到在完成时得到通知的合理方法。另外,我也不能放入progressBar.visibility = View.GONE新线程,因为只有UI线程才允许进行此类操作。
我是协程的新手,所以我不太明白我在这里缺少什么。
Ser*_*gey 20
要使用协程,您需要做几件事:
通常我为此使用一个单独的类,例如"Presenter" 或 "ViewModel":
class Presenter : CoroutineScope {
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job // to run code in Main(UI) Thread
// call this method to cancel a coroutine when you don't need it anymore,
// e.g. when user closes the screen
fun cancel() {
job.cancel()
}
fun execute() = launch {
onPreExecute()
val result = doInBackground() // runs in background thread without blocking the Main Thread
onPostExecute(result)
}
private suspend fun doInBackground(): String = withContext(Dispatchers.IO) { // to run code in Background Thread
// do async work
delay(1000) // simulate async work
return@withContext "SomeResult"
}
// Runs on the Main(UI) Thread
private fun onPreExecute() {
// show progress
}
// Runs on the Main(UI) Thread
private fun onPostExecute(result: String) {
// hide progress
}
}
Run Code Online (Sandbox Code Playgroud)
使用ViewModel以下代码更简洁viewModelScope:
class MyViewModel : ViewModel() {
fun execute() = viewModelScope.launch {
onPreExecute()
val result = doInBackground() // runs in background thread without blocking the Main Thread
onPostExecute(result)
}
private suspend fun doInBackground(): String = withContext(Dispatchers.IO) { // to run code in Background Thread
// do async work
delay(1000) // simulate async work
return@withContext "SomeResult"
}
// Runs on the Main(UI) Thread
private fun onPreExecute() {
// show progress
}
// Runs on the Main(UI) Thread
private fun onPostExecute(result: String) {
// hide progress
}
}
Run Code Online (Sandbox Code Playgroud)
要使用viewModelScope将下一行添加到应用程序的build.gradle文件的依赖项:
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION"
Run Code Online (Sandbox Code Playgroud)
在撰写本文时 final LIFECYCLE_VERSION = "2.3.0-alpha04"
小智 5
您可以让 ProgressBar 在 UI 主线程上运行,同时使用协程异步运行您的任务。
在你的覆盖 fun onCreate() 方法中,
GlobalScope.launch(Dispatchers.Main) { // Coroutine Dispatcher confined to Main UI Thread
yourTask() // your task implementation
}
Run Code Online (Sandbox Code Playgroud)
你可以初始化,
private var jobStart: Job? = null
Run Code Online (Sandbox Code Playgroud)
在 Kotlin 中,var 声明意味着属性是可变的。如果将其声明为 val,则它是不可变的、只读的且无法重新分配。
在 onCreate() 方法之外, yourTask() 可以实现为一个挂起函数,它不会阻塞主调用者线程。
当函数在等待返回结果时被挂起时,它的运行线程会被解除阻塞以供其他函数执行。
private suspend fun yourTask() = withContext(Dispatchers.Default){ // with a given coroutine context
jobStart = launch {
try{
// your task implementation
} catch (e: Exception) {
throw RuntimeException("To catch any exception thrown for yourTask", e)
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于您的进度条,您可以创建一个按钮以在单击该按钮时显示进度条。
buttonRecognize!!.setOnClickListener {
trackProgress(false)
}
Run Code Online (Sandbox Code Playgroud)
在 onCreate() 之外,
private fun trackProgress(isCompleted:Boolean) {
buttonRecognize?.isEnabled = isCompleted // ?. safe call
buttonRecognize!!.isEnabled // !! non-null asserted call
if(isCompleted) {
loading_progress_bar.visibility = View.GONE
} else {
loading_progress_bar.visibility = View.VISIBLE
}
}
Run Code Online (Sandbox Code Playgroud)
另一个提示是检查您的协程是否确实在另一个线程上运行,例如。DefaultDispatcher-worker-1,
Run Code Online (Sandbox Code Playgroud)Log.e("yourTask", "Running on thread ${Thread.currentThread().name}")
希望这是有帮助的。
另一种方法是在 上创建通用扩展函数CoroutineScope:
fun <R> CoroutineScope.executeAsyncTask(
onPreExecute: () -> Unit,
doInBackground: () -> R,
onPostExecute: (R) -> Unit
) = launch {
onPreExecute()
val result = withContext(Dispatchers.IO) { // runs in background thread without blocking the Main Thread
doInBackground()
}
onPostExecute(result)
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以将它与 any 一起使用CoroutineScope:
class MyViewModel : ViewModel() {
fun someFun() {
viewModelScope.executeAsyncTask(onPreExecute = {
// ...
}, doInBackground = {
// ...
"Result" // send data to "onPostExecute"
}, onPostExecute = {
// ... here "it" is a data returned from "doInBackground"
})
}
}
Run Code Online (Sandbox Code Playgroud)
在Activity或Fragment:
lifecycleScope.executeAsyncTask(onPreExecute = {
// ...
}, doInBackground = {
// ...
"Result" // send data to "onPostExecute"
}, onPostExecute = {
// ... here "it" is a data returned from "doInBackground"
})
Run Code Online (Sandbox Code Playgroud)
要在应用程序的build.gradle文件的依赖项中使用viewModelScope或lifecycleScope添加下一行:
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
Run Code Online (Sandbox Code Playgroud)
在撰写本文时final LIFECYCLE_VERSION = "2.3.0-alpha05"。
| 归档时间: |
|
| 查看次数: |
10197 次 |
| 最近记录: |