Home > Enterprise >  Kotlin executes only one of two suspend functions
Kotlin executes only one of two suspend functions

Time:09-14

In my suspend function getContent I am calling two other suspend functions:

override suspend fun getContent(token: String) {
...
                    getUserPosts(token)
                    getRecentPosts(token)
    ...

}

But only the first one gets executed. If I put getRecentPosts first then only that one gets executed.

How to solve this?

I call the getContent method from ViewModel with viewModelScope.

EDIT Here is my getUserPosts() method, the getRecentPosts() method look pretty much the same, the "Finished 1" and "Finsihed 2" Log is getting logged but not "Finished 3:

override suspend fun getUserPosts(token: String) {
    try {
        myInterceptor.setAccessToken(token)
        graphqlAPI.query(GetUserPostsQuery()).fetchPolicy(FetchPolicy.NetworkFirst).watch()
            .collect { response ->
                val newList = arrayListOf<Post>()
                response.data?.getUserPosts?.let {
                    for (post in it) {
                        newList.add(
                            Post(
                                id = post.postFragment.id,
                                ...
                            )
                        )

                    }
                    userState.editUserState(userState.userStateFlow.value?.copy(posts = newList))
                    Log.i("# #", "Finished 1")
                }
                Log.i("# #", "Finished 2")
            }
        Log.i("# #", "Finished 3")
    } catch (e: ApolloException) {
        e.printStackTrace()
    }
}

CodePudding user response:

collect never stops, so the first function will never end.

What you have to do is launch another coroutine inside.

override suspend fun getContent(token: String) {
      CoroutineContex.launch { getUserPosts(token) }                    
      CoroutineContex.launch { getRecentPosts(token) }

}

However that is considered dirty because you can't test it. That launch there won't have the same scope than the coroutine scope from testing. Also, it won't stop, so it is better to provide the coroutine scope.

override suspend fun getContent(token: String, coroutineScope: CoroutineScope) {
      coroutineScope.launch { getUserPosts(token) }                    
      coroutineScope.launch { getRecentPosts(token) }

}

This way in your view model or fragment you can call it "safely" by knowing the scope will cancel the collection when the owner life cycle ends.

getContent(token, viewModelScope)
getContent(token, viewLifeCycleOwner.lifecycleScope)

This is not an uncommon doubt, and there is a fairly brief mention on the documentation: https://developer.android.com/topic/libraries/architecture/coroutines#lifecycle-aware

  • Related