嗨,我在一个项目中使用 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) 最近,我将协程应用到我的项目中,一切似乎都很好,但今天我遇到了一个问题,使用协程 + 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)
我的问题是:如何暂停协程的执行以等待改造的回调?
我试图理解 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
用例:我有很多操作想要从主线程异步发生,但又彼此并行。
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
我使用 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()
最近我一直在详细学习协程,据我所知,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) 我正在尝试使用 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)
应用程序编程接口: …
我需要在自定义视图中使用协程。看完这个演讲,我相信我最好的选择是使用lifecycleScope作为协程范围,这样当lifecycleowner被销毁时它会自动取消。
但是我似乎无法访问自定义视图中的生命周期范围。根据文档,我们可以从生命周期对象 aslifecycle.coroutineScope或从生命周期所有者as访问它lifecycleOwner.lifecycleScope。但是自定义视图不是生命周期所有者。那么我可以以某种方式访问片段的生命周期范围吗?或者如果我不能,我应该使用哪个协程上下文?
android android-custom-view kotlin-coroutines coroutinescope
我使用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
我正在使用 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
coroutinescope ×10
kotlin ×9
android ×8
async-await ×1
asynchronous ×1
coroutine ×1
retrofit ×1
retrofit2 ×1