⚡ Sangsakala Proxy 🏠 Home
Skip to content

Android: Frame navigation stalls after activity.recreate() #11591

Open

Description

@rigor789

Environment

  • @nativescript/core 9.1.1, @nativescript/android 9.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

  1. Use a Frame as the root view and navigate forward at least once.
  2. Call recreate() on the window's activity, for example frame.getNativeWindow().android.activity.recreate().
  3. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions