Repository navigation
Description
Environment
@nativescript/core9.1.1,@nativescript/android9.1.1- Reproduced on Android emulators running API 35 and API 37
Describe the bug
After the activity is recreated programmatically with activity.recreate(), the root Frame stops processing navigation. frame.goBack() and frame.navigate() add an entry to the navigation queue, but it never runs. The system back button then finishes the activity: the queued back entries count against canGoBack(), so the frame reports nothing to go back to.
Activity recreation caused by a system configuration change (for example, a font scale change) does not have this problem.
Cause
The recreated activity attaches the Frame's new native view while its lifecycle is still INITIALIZED, before onCreate has returned. Frame._onAttachedToWindow returns early in that state:
const lifecycleState = activity?.getLifecycle?.()?.getCurrentState() || androidx.lifecycle.Lifecycle.State.CREATED;
if ((this._manager && this._manager.isDestroyed()) || !lifecycleState.isAtLeast(androidx.lifecycle.Lifecycle.State.CREATED)) {
return;
}
this._attachedToWindow = true;
this._isReset = false;
this._processNextNavigationEntry();No other attach event follows, so _isReset stays true and _attachedToWindow stays false. _processNextNavigationEntry then returns early on this._isReset && !this._attachedToWindow for every later navigation.
Trace from wrapping the Frame methods (activity is the window's activity, which is also the current activity at every step):
recreate()
disposeNativeView before: activity=DESTROYED isReset=false
_onRootViewReset after: attachedToWindow=false isReset=true
initNativeView before: activity=INITIALIZED isReset=true
_onAttachedToWindow before: activity=INITIALIZED isReset=true
_onAttachedToWindow after: attachedToWindow=false isReset=true <- guard bails
frame.goBack() queue=1 executing=false isReset=true attachedToWindow=false
frame.goBack() queue=2 executing=false isReset=true attachedToWindow=false
With a font-scale change instead, the attach arrives once the activity is RESUMED and navigation keeps working:
_onAttachedToWindow before: activity=RESUMED isReset=true
_onAttachedToWindow after: attachedToWindow=true isReset=false
To reproduce
- Use a
Frameas the root view and navigate forward at least once. - Call
recreate()on the window's activity, for exampleframe.getNativeWindow().android.activity.recreate(). - Call
frame.goBack(), or press the system back button.
Expected: the frame navigates back.
Actual: nothing happens. The system back button closes the app.
Possible fix
When the guard rejects the attach because the activity isn't CREATED yet, the frame could retry once the activity's lifecycle reaches CREATED, for example through a lifecycle observer or by posting to the native view, instead of waiting for an attach event that never comes.
Additional context
I found this while testing nativescript-vue's handling of recreated windows (nativescript-vue/nativescript-vue#1187). The traces above come from that demo app, but the stall is in core and plain frame.goBack() hits it too.
Activity