标签: coroutinescope

从使用 Kotlin 协程调用挂起函数的普通函数返回值

嗨,我在一个项目中使用 Kotlin 协程库。

下面的方法调用一个挂起函数,它返回一个布尔值。

fun isNetworkAvailable(context: Context?): Boolean {
            //return checkNetworkReachability(context)
            var isNetworkAvailable = false
            GlobalScope.launch(Dispatchers.Default) {
                isNetworkAvailable = GlobalScope.async<Boolean> {
                    checkNetwork()

                }.await()
            }
            return isNetworkAvailable

        }
Run Code Online (Sandbox Code Playgroud)

这里的 checkNetwork 是挂起函数。在执行之前,返回值被传递给调用者(视图/活动)。如果不将“isNetworkAvailable”设为挂起,我该如何实现?。

在 checkNetwork 方法中,检查可达性调用网络调用,如下所示。

private suspend fun checkNetwork() : Boolean {
            val value = GlobalScope.async<Boolean> {
                val isEastReachable = async { checkEastReachable() }
                if (!isEastReachable.await()) {
                    checkWestReachable()
                } else {
                    true
                }
            }

            return value.await()
        }
Run Code Online (Sandbox Code Playgroud)

子方法是

private suspend fun checkEastReachable(): Boolean = coroutineScope {

                withContext(Dispatchers.Default) {
                    repository.networkManager.callReachableEast()
                }
            }



private …
Run Code Online (Sandbox Code Playgroud)

android async-await kotlin kotlin-coroutines coroutinescope

4
推荐指数
1
解决办法
3634
查看次数

暂停协程的执行以等待回调

最近,我将协程应用到我的项目中,一切似乎都很好,但今天我遇到了一个问题,使用协程 + Retrofit 将文件/图像上传到服务器

使用协程+Retrofit上传文件似乎没有解决方案,所以必须使用回调进行Retrofit。

//Api interface
interface UploadFileApiKotlin {
    @Multipart
    @POST("/uploadFileApi")
    fun uploadFiles(
        @Part listUri: List<MultipartBody.Part>
    ): Call<Response<List<FileResponse>?>>
}
//ViewModel class
serviceScope.launch {
                //Insert into db
                repository.insertNewExtAct()
                //Send data into server.
                val call = RequestHelper.getUpLoadFilesKotlinRequest().uploadFiles(partList)
                call.enqueue(object : Callback<Response<List<FileResponse>?>> {
                    override fun onResponse(
                        call: Call<Response<List<FileResponse>?>>,
                        response: Response<Response<List<FileResponse>?>>
                    ) {
                        TODO("Not yet implemented")
                    }

                    override fun onFailure(
                        call: Call<Response<List<FileResponse>?>>,
                        t: Throwable
                    ) {
                        TODO("Not yet implemented")
                    }
                })
                //Wait for response from server and do logic
            }
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何暂停协程的执行以等待改造的回调?

android kotlin retrofit2 kotlin-coroutines coroutinescope

4
推荐指数
1
解决办法
7028
查看次数

Kotlin:调用 CoroutineScope.launch 与在协程内启动之间的区别

我试图理解 Kotlin 中的结构化并发,但无法理解这段代码。

fun main(): Unit = runBlocking {
    other(this)
}

suspend fun other(scope: CoroutineScope) {
    val job = scope.launch {
        scope.launch {
            delay(200)
            println("e")
        }
        println("a")
    }
    job.invokeOnCompletion {
        println("Complete")
    }
}
Run Code Online (Sandbox Code Playgroud)

代码打印出来

a
Complete
e
Run Code Online (Sandbox Code Playgroud)

如果我用 替换内部scope.launch调用launch,就像这样

suspend fun other(scope: CoroutineScope) {
    val job = scope.launch {
       launch {
            delay(200)
            println("e")
        }
        println("a")
    }
    job.invokeOnCompletion {
        println("Complete")
    }
}
Run Code Online (Sandbox Code Playgroud)

它打印

a
e
Complete
Run Code Online (Sandbox Code Playgroud)

这表明第一个示例不遵循结构化并发,因为父作业先于子作业完成。我的困惑是,为什么会发生这种情况?

我觉得在这种情况下scope.launch可能相当于调用launch(应该相当于this.launch并且 this 指的是scope …

kotlin kotlin-coroutines coroutinescope structured-concurrency

4
推荐指数
1
解决办法
343
查看次数

通过标签 Kotlin 从内部嵌套协程返回

用例:我有很多操作想要从主线程异步发生,但又彼此并行。

val scope = CoroutineScope(Dispatchers.IO)
val items = // List of items to do something.

scope.launch {
    items.forEach { item ->
        scope.launch {
            if (itemFailsValidation(item)) {
                // Here I want to skip this item but continue the forEach loop.
                return@launch // "There is more than one label with such a name in this" scope"
            }
            doSomethingThatMightTakeABit(item)
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试添加标签,例如inner@scope.launch,编辑器会说“标签是多余的,因为它不能在 ''break''、''Continue'' 或 ''return'' 表达式中引用”

有谁知道这样做的好方法?

asynchronous coroutine kotlin kotlin-coroutines coroutinescope

3
推荐指数
1
解决办法
1882
查看次数

继续从回调中挂起函数

我使用 firestore 作为后端数据库,保存数据如下所示:

suspend fun uploadDataToFirestore() {
  val firestore = Firebase.firestore
  var batch = firestore.batch
 
 -- fill batch with data --

  batch.commit().addOnCompleteListener {
    if (it.isSuccessful) {
      Timber.d("Successfully saved data")
     
      doAdditionalSuspendingStuff()
            
    } else {
      Timber.d("error at saving data: ${it.exception}")     
    }
}
 
Run Code Online (Sandbox Code Playgroud)

问题出在内部,onCompleteListener因为我无法调用额外的挂起函数。有没有办法从onCompleteListenerbut 内部调用挂起函数,以便它们仍然附加到相同的作用域,因为我不希望函数在执行uploadDataToFirestore之前完成。doAdditionalSuspendingStuff()

android kotlin kotlin-coroutines coroutinescope

3
推荐指数
1
解决办法
1060
查看次数

CoroutineScope 与 SupervisorJob 对比 SupervisorScope

最近我一直在详细学习协程,据我所知,SupervisorJob()如果协程的子级之一由于某种原因被取消,我们有机会不取消所有子级。

据说以 开头的协程coroutineScope如果失败了,会取消所有子协程,但以 开头的协程supervisorScope只会取消失败的子协程

我想知道是否可以CoroutineScope通过添加SupervisorJobCoroutineContext 来改变行为,但我无法获得预期的行为,这是我没有得到的

预期行为 - getData1() 和 getData3() 结果被打印*

实际: - getData2() 取消所有协程

fun main() = runBlocking {

    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        println(throwable)
    }

    val customScope = CoroutineScope(SupervisorJob() + exceptionHandler)


    customScope.launch {
        launch {
            getData1().also { println(it) }
        }
        launch {
            getData2().also { println(it) }
        }
        launch {
            getData3().also { println(it) }
        }
     }.join()

}


private suspend fun getData1(): String? {
    delay(1000) …
Run Code Online (Sandbox Code Playgroud)

android kotlin kotlin-coroutines coroutinescope

2
推荐指数
1
解决办法
2144
查看次数

未解决的参考:等待。Kotlin 协程

我正在尝试使用 Retrofit 2 和协程从 Api 获取数据。从我的 GetRepositoriesUseCase 中,我启动了协程,但“await()”函数是一个未解析的引用。

视图模型:

fun getRepositoryList()  {
    getRepositoriesUseCase(textLiveData.value.toString(), viewModelScope) { result ->
        result.onSuccess { repositoriesList.value = it }
        result.onFailure { show(it.message.toString()) }
    }
}
Run Code Online (Sandbox Code Playgroud)

获取存储库用例:

class GetRepositoriesUseCase(private val repository: ApiRepository) {

operator fun invoke(
    key: String,
    coroutineScope: CoroutineScope,
    onResult: (Result<Collection<Repository>>) -> Unit
) {
    coroutineScope.launch {
        val result = withContext(Dispatchers.IO) {
            runCatching { repository.getRepositories(key) }
        }
        onResult(result)
    }
}}
Run Code Online (Sandbox Code Playgroud)

ApiRepository(这里出现错误):

class ApiRepository(private val api: GitHubApi) {

fun getRepositories(key: String): Collection<Repository> {
    return api.getRepository(key).await().list
}}
Run Code Online (Sandbox Code Playgroud)

应用程序编程接口: …

android kotlin retrofit kotlin-coroutines coroutinescope

1
推荐指数
1
解决办法
3971
查看次数

如何从自定义视图访问宿主片段的生命周期范围?

我需要在自定义视图中使用协程。看完这个演讲,我相信我最好的选择是使用lifecycleScope作为协程范围,这样当lifecycleowner被销毁时它会自动取消。

但是我似乎无法访问自定义视图中的生命周期范围。根据文档,我们可以从生命周期对象 aslifecycle.coroutineScope或从生命周期所有者as访问它lifecycleOwner.lifecycleScope。但是自定义视图不是生命周期所有者。那么我可以以某种方式访问​​片段的生命周期范围吗?或者如果我不能,我应该使用哪个协程上下文?

android android-custom-view kotlin-coroutines coroutinescope

1
推荐指数
1
解决办法
1911
查看次数

如何在 MainActivity 中管理协程并等待完成?

我使用GlobalScopewith runBlockingin MainActivity,但我不使用那里的流程,只是挂起功能。我想GlobalScope从协程更改为其他范围。

用例

class UpdateNotificationListItemUseCase @Inject constructor(private val notificationDao: NotificationDao): BaseUpdateBooleanUseCase<Int, Boolean, Boolean, Boolean, Unit>() {
    override suspend fun create(itemId: Int, isRead: Boolean, isArchived: Boolean, isAccepted: Boolean){
        notificationDao.updateBooleans(itemId, isRead, isArchived, isAccepted)
    }
}
Run Code Online (Sandbox Code Playgroud)

主要活动

val job = GlobalScope.launch { vm.getIdWithUpdate() }
runBlocking {
    job.join()
}
Run Code Online (Sandbox Code Playgroud)

主视图模型

suspend fun getIdWithUpdate() {
     var id = ""
     id = notificationAppSessionStorage.getString(
            notificationAppSessionStorage.getIncomingKeyValueStorage(),
            ""
        )
        if (id != "") {
           
            updateNotificationListItemUseCase.build(id.toInt(), true, false, false)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的建议: …

android android-activity kotlin kotlin-coroutines coroutinescope

1
推荐指数
1
解决办法
3252
查看次数

Kotlin Android - 分派到主线程的正确方法

我正在使用 OkHttp 库从互联网下载一些数据,然后androidx.lifecycle.ViewModel 我想更新我的LiveData. 似乎从后台线程执行此操作会引发异常,如下所示:

2022-01-17 15:47:59.589 7354-7396/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
    Process: com.example.myapplication, PID: 7354
    java.lang.IllegalStateException: Cannot invoke setValue on a background thread
        at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487)
        at androidx.lifecycle.LiveData.setValue(LiveData.java:306)
        at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
        at com.example.myapplication.MainActivityViewModel$getOneMoreCat$1.invoke(MainActivityViewModel.kt:86)
        at com.example.myapplication.MainActivityViewModel$getOneMoreCat$1.invoke(MainActivityViewModel.kt:39)
        at com.example.myapplication.singleton.CommunicationManager$sendRequest$1.onResponse(CommunicationManager.kt:24)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)
Run Code Online (Sandbox Code Playgroud)

现在我找到了两种不同的方法来调度到主线程ViewModel(根据 AAC 指南,它没有引用 Context),请参见此处:

            GlobalScope.launch {
                withContext(Dispatchers.Main) {
                    // do whatever, e.g. update LiveData
                }
            }
Run Code Online (Sandbox Code Playgroud)

或者

            Handler(Looper.getMainLooper()).post(Runnable {
                   // do whatever, e.g. update LiveData
            })
Run Code Online (Sandbox Code Playgroud)

哪个是正确的方法?也就是说,在运行时影响最小。

更新我确实发现我也可以这样做myLiveData.post() …

android kotlin android-livedata kotlin-coroutines coroutinescope

0
推荐指数
1
解决办法
5838
查看次数