question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SharedFlow didn't cancel or throw exception with callbackFlow

See original GitHub issue

The exception didn’t throw to parent scope or cancel itself while using SharedFlow with callbackFlow. I tried to cancel sharedflow in case of failure. Here is my code snippet

fun adapt(call: Call<T>): SharedFlow<T> {
        val scope = CoroutineScope(dispatcher)
        return callbackFlow<T> {
            call.enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    sendBlocking(response.body())
                    close()
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    close(t)
                }
            })
            awaitClose()
        }.catch {
            /**
             *Here caught exception that threw in Failure case
             * Try to cancel Job so SharedFlow can terminate but It didn't work However catching exception here won't crash my app
             */
            scope.cancel()
        }.shareIn(scope, SharingStarted.Lazily, 1)
    }

I used it

runBlocking{

//this will get first output in case of success and then completed this coroutine
//But In case of Failure, this will always wait to get the first item and never completed

    val result = adapt(someCall).first()
}

Here is another way tried to accomplish the same thing

fun adapt(call: Call<T>): SharedFlow<T> {
        val scope = CoroutineScope(dispatcher)
        return callbackFlow<T> {
            call.enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    sendBlocking(response.body())
                    close()
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    close(t)
                }
            })
            awaitClose()
        }.shareIn(scope, SharingStarted.Lazily, 1).catch {
            /**
             *This catch block never invoked in case of failure
             * Try to cancel Job so sharedFlow can terminate its coroutine
             */
              currentCoroutineContext().cancel()
        }
    }

I used this as previous but this time

runBlocking{
//this will get first output in case of success and then completed this coroutine
//But In case of Failure App crashes
    val result = adapt(someCall).first()

}

sharedflow.collect|first()|take(1){} stays always in resume state I want to cancel it in case of failure.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
elizarovcommented, Nov 5, 2020

catch on SharedFlow is meaningless, since SharedFlow never completes. I’ll add the corresponding Lint checks with warnings to explain it.

0reactions
waqasakram117commented, Nov 5, 2020

Yes this is a nice trick but I wonder why

val flow = callbackFlow { ... }
   .shareIn(....) 
   .catch(...)//this won't work

catch after shareIn didn’t catch anything and app crashes. And

val flow = callbackFlow { ... }
    .catch { e -> 
      scope.cancel()
    }
   .shareIn(scope,.,.) 

Didn’t work.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Kotlin Flow: unsubscribe from SharedFlow when Fragment ...
After changing collection scope to viewModelScope , I was getting ChildCancelledException: Child of the scoped flow was cancelled exception ...
Read more >
From RxJava to Kotlin Flow: Error Handling - ProAndroidDev
First of all, for our comparison, we'll create helper functions of Flow and Observable, which emit a value and then throw an exception....
Read more >
Handle exceptions in callbackFlow with Kotlin | by Florent Blot
In order to propagate the exception, we have two choices: cancelling its coroutine's scope or closing its channel. Cancelling the scope can be...
Read more >
Kotlin flows on Android - Android Developers
In coroutines, a flow is a type that can emit multiple values sequentially, as opposed to suspend functions that return only a single...
Read more >
SharedFlow - Kotlin
This usually happens when the scope in which the coroutine is running is cancelled. A subscriber to a shared flow is always cancellable,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found