Skip to content
This repository was archived by the owner on Jan 10, 2025. It is now read-only.

[Paging with Network] Fix consumeAsFlow can be collected just once #892

Conversation

eneim
Copy link
Contributor

@eneim eneim commented Aug 17, 2020

The issue

Currently, the Paging with Network demo uses ReceiveChannel.consumeAsFlow which crashes the App on configuration changes. The reason, IMO, is when the Activity is recreated, the ViewModel's posts value starts collecting again for the new Adapter. This goes against the contract of consumeAsFlow which allows up to one consumer.

How to reproduce:

  • Open the PagingWithNetwork sample, choose any of the demos, I picked the "NETWORK ONLY (BY ITEM)".
  • After the first loading finishes, rotate the device -> It crashes. Stack trace is as below:
    Process: com.android.example.paging.pagingwithnetwork, PID: 21282
    java.lang.IllegalStateException: ReceiveChannel.consumeAsFlow can be collected just once
        at kotlinx.coroutines.flow.ChannelAsFlow.markConsumed(Channels.kt:125)
        at kotlinx.coroutines.flow.ChannelAsFlow.collect(Channels.kt:150)
        at com.android.example.paging.pagingwithnetwork.reddit.ui.SubRedditViewModel$$special$$inlined$map$1.collect(SafeCollector.common.kt:114)
        at kotlinx.coroutines.flow.internal.ChannelFlowMerge$collectTo$$inlined$collect$1$lambda$1.invokeSuspend(Merge.kt:67)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at androidx.lifecycle.DispatchQueue.drainQueue(DispatchQueue.kt:76)
        at androidx.lifecycle.DispatchQueue.resume(DispatchQueue.kt:55)
        at androidx.lifecycle.LifecycleController$observer$1.onStateChanged(LifecycleController.kt:40)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:361)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:300)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:339)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:145)
        at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:131)
        at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:68)
        at androidx.lifecycle.ReportFragment$LifecycleCallbacks.onActivityPostCreated(ReportFragment.java:170)
        at android.app.Activity.dispatchActivityPostCreated(Activity.java:1216)
        at android.app.Activity.performCreate(Activity.java:7821)
        at android.app.Activity.performCreate(Activity.java:7801)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3298)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3462)
        at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5429)
        at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5337)
        at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2063)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7615)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)

The fix

This PR use the ReceiveChannel.receiveAsFlow instead. It allows multiple receivers.

@dlam
Copy link
Contributor

dlam commented Aug 18, 2020

Thanks for this!

@dlam dlam merged commit 35e2721 into android:master Aug 18, 2020
@eneim eneim deleted the feature/fix-ReceiveChannel-consumeAsFlow-can-be-collected-just-once branch August 22, 2020 03:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants