https://kotlinlang.org logo
#compose
Title
# compose
c

Chris Fillmore

04/27/2022, 4:02 PM
I am trying to implement a timeout on app backgrounding, because I have several open socket connections with stateful services. I am using Compose navigation with a VM scoped to a “Main” screen.
So I have something like this:
Copy code
composable(Main.name) { navBackStackEntry ->

  // MyViewModel holds a component with several open connections, which I want to clean up
  // if the app is in the backgrounding for some amount of time.
  val viewModel = hiltViewModel<MyViewModel>(navBackStackEntry)
  val lifecycleOwner = LocalLifecycleOwner.current

  DisposableEffect(lifecycleOwner) {
    val observer = object: DefaultLifecycleObserver {
      override fun onStart(owner: LifecycleOwner) {
        val didTimeOut = viewModel.cancelTimeout()
        if (didTimeOut) {
          navController.popBackStack()
        }
      }

      override fun onStop(owner: LifecycleOwner) {
        viewModel.startTimeout()
      }
    }
    lifecycleOwner.lifecycle.addObserver(observer)

    onDispose {
      lifecycleOwner.lifecycle.removeObserver(observer)
    }
  }
}
My approach as you can see, is to try popping the back stack if the timeout completed. But this leads to an exception.
Copy code
E  java.util.NoSuchElementException
E      at java.util.AbstractList$Itr.next(AbstractList.java:377)
E      at androidx.navigation.NavController.lifecycleObserver$lambda-2(NavController.kt:183)
E      at androidx.navigation.NavController.$r8$lambda$QcvT-AhOyhL9f0B2nrlZ1aMydmQ(Unknown Source:0)
E      at androidx.navigation.NavController$$ExternalSyntheticLambda0.onStateChanged(Unknown Source:2)
E      at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
E      at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
E      at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
E      at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
E      at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
E      at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:68)
E      at androidx.lifecycle.ReportFragment$LifecycleCallbacks.onActivityPostStarted(ReportFragment.java:187)
E      at android.app.Activity.dispatchActivityPostStarted(Activity.java:1396)
E      at android.app.Activity.performStart(Activity.java:8268)
E      at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3872)
E      at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
E      at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
E      at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
E      at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
E      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2336)
E      at android.os.Handler.dispatchMessage(Handler.java:106)
E      at android.os.Looper.loop(Looper.java:246)
E      at android.app.ActivityThread.main(ActivityThread.java:8653)
E      at java.lang.reflect.Method.invoke(Native Method)
E      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
E      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
So I conclude I can’t call
popBackStack()
like this.
Basically I am trying to “reset” this composable with a new VM. Any recommendations?
7 Views