hotwired / turbo-android

Android framework for making Turbo native apps
MIT License
424 stars 50 forks source link

Fix resetting the `TurboSessionNavHostFragment` #251

Closed jayohms closed 1 year ago

jayohms commented 1 year ago

Newer versions of the navigation library do not recreate/clear the backstack when updating the nav graph in NavController.setGraph() if it's identical to the existing one. This brings back the previous behavior of TurboSessionNavHostFragment.reset() by using a random Int as a graph unique_instance argument.

This also switches to String-based routes instead of using an ID, since the navigation library has deprecated the ID-based approach.

jayohms commented 1 year ago

The original approach is too naive and will not work 😩. Got this crash when the app tried to restore the backstack when resuming from the background. The destination routes need to be identical across app restores so the original destination in the backstack can be found.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.basecamp.hey/com.basecamp.hey.main.MainActivity}: java.lang.IllegalStateException: Restoring the Navigation back stack failed: destination 1667411784 cannot be found from the current destination NavGraph(0x0) startDestination={Destination(0x982b2ff6) route=1265450921 class=com.basecamp.hey.feature.boxes.inbox.InboxFragment}
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3676)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813)
  at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5791)
  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5682)
  at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71)
  at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
  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:2308)
  at android.os.Handler.dispatchMessage(Handler.java:106)
  at android.os.Looper.loopOnce(Looper.java:201)
  at android.os.Looper.loop(Looper.java:288)
  at android.app.ActivityThread.main(ActivityThread.java:7898)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Caused by: java.lang.IllegalStateException: Restoring the Navigation back stack failed: destination 1667411784 cannot be found from the current destination NavGraph(0x0) startDestination={Destination(0x982b2ff6) route=1265450921 class=com.basecamp.hey.feature.boxes.inbox.InboxFragment}
  at androidx.navigation.NavController.onGraphCreated(NavController.kt:1128)
  at androidx.navigation.NavController.setGraph(NavController.kt:1086)
  at androidx.navigation.NavController.setGraph(NavController.kt:100)
  at dev.hotwire.turbo.session.TurboSessionNavHostFragment.initControllerGraph(TurboSessionNavHostFragment.kt:66)
  at dev.hotwire.turbo.session.TurboSessionNavHostFragment.onCreate(TurboSessionNavHostFragment.kt:28)
  at androidx.fragment.app.Fragment.performCreate(Fragment.java:3090)
  at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
  at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257)
  at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
  at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1433)
  at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2977)
  at androidx.fragment.app.FragmentManager.dispatchCreate(FragmentManager.java:2884)
  at androidx.fragment.app.FragmentController.dispatchCreate(FragmentController.java:252)
  at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:220)
  at com.basecamp.hey.base.BaseActivity.onCreate(BaseActivity.kt:23)
  at com.basecamp.hey.main.MainActivity.onCreate(MainActivity.kt:43)
  at android.app.Activity.performCreate(Activity.java:8290)
  at android.app.Activity.performCreate(Activity.java:8269)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) 
  at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5791) 
  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5682) 
  at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71) 
  at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45) 
  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:2308) 
  at android.os.Handler.dispatchMessage(Handler.java:106) 
  at android.os.Looper.loopOnce(Looper.java:201) 
  at android.os.Looper.loop(Looper.java:288) 
  at android.app.ActivityThread.main(ActivityThread.java:7898) 
  at java.lang.reflect.Method.invoke(Native Method) 
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)Â