fix(android): nested frames were sometimes not recreated (#9725)

BREAKING CHANGE:

AndroidFragmentCallbacks now requires onResume as well

Migration steps:
specify onResume on custom fragment implementations
This commit is contained in:
Eduardo Speroni
2021-12-31 13:39:54 -03:00
committed by Nathan Walker
parent 638388244e
commit 902a4c6afc
4 changed files with 38 additions and 0 deletions

View File

@ -19,6 +19,10 @@ const FragmentClass = (<any>org.nativescript.widgets.FragmentBase).extend('com.t
this._callbacks.onPause(this, superProto.onPause);
},
onResume(): void {
this._callbacks.onResume(this, superProto.onResume);
},
onCreate(savedInstanceState: android.os.Bundle) {
if (!this._callbacks) {
setFragmentCallbacks(this);

View File

@ -51,6 +51,7 @@ export interface ExpandedEntry extends BackstackEntry {
frameId: number;
isNestedDefaultTransition: boolean;
isAnimationRunning: boolean;
}
export function _setAndroidFragmentTransitions(animated: boolean, navigationTransition: NavigationTransition, currentEntry: ExpandedEntry, newEntry: ExpandedEntry, frameId: number, fragmentTransaction: androidx.fragment.app.FragmentTransaction, isNestedDefaultTransition?: boolean): void {
@ -60,6 +61,7 @@ export function _setAndroidFragmentTransitions(animated: boolean, navigationTran
if (entries && entries.size > 0) {
throw new Error('Calling navigation before previous navigation finish.');
}
newEntry.isAnimationRunning = false;
allowTransitionOverlap(currentFragment);
allowTransitionOverlap(newFragment);
@ -227,6 +229,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener {
if (Trace.isEnabled()) {
Trace.write(`START ${animator.transitionType} for ${entry.fragmentTag}`, Trace.categories.Transition);
}
entry.isAnimationRunning = true;
}
onAnimationRepeat(animator: ExpandedAnimator): void {
@ -239,6 +242,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener {
if (Trace.isEnabled()) {
Trace.write(`END ${animator.transitionType} for ${animator.entry.fragmentTag}`, Trace.categories.Transition);
}
animator.entry.isAnimationRunning = false;
transitionOrAnimationCompleted(animator.entry, animator.backEntry);
}
@ -246,6 +250,7 @@ function getAnimationListener(): android.animation.Animator.AnimatorListener {
if (Trace.isEnabled()) {
Trace.write(`CANCEL ${animator.transitionType} for ${animator.entry.fragmentTag}`, Trace.categories.Transition);
}
animator.entry.isAnimationRunning = false;
}
}

View File

@ -237,6 +237,21 @@ export class Frame extends FrameBase {
this.backgroundColor = this._originalBackground;
this._originalBackground = null;
}
setTimeout(() => {
// there's a bug with nested frames where sometimes the nested fragment is not recreated at all
// so we manually check on loaded event if the fragment is not recreated and recreate it
const currentEntry = this._currentEntry || this._executingContext?.entry;
if (currentEntry) {
if (!currentEntry.fragment) {
const manager = this._getFragmentManager();
const transaction = manager.beginTransaction();
currentEntry.fragment = this.createFragment(currentEntry, currentEntry.fragmentTag);
_updateTransitions(currentEntry);
transaction.replace(this.containerViewId, currentEntry.fragment, currentEntry.fragmentTag);
transaction.commitAllowingStateLoss();
}
}
}, 0);
super.onLoaded();
}
@ -1002,6 +1017,19 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
}
}
@profile
public onResume(fragment: org.nativescript.widgets.FragmentBase, superFunc: Function): void {
const frame = this.entry.resolvedPage.frame;
// on some cases during the first navigation on nested frames the animation doesn't trigger
// we depend on the animation (even None animation) to set the entry as the current entry
// animation should start between start and resume, so if we have an executing navigation here it probably means the animation was skipped
// so we manually set the entry
if (frame._executingContext && !(<any>this.entry).isAnimationRunning) {
frame.setCurrent(this.entry, frame._executingContext.navigationType);
}
superFunc.call(fragment);
}
@profile
public onStop(fragment: androidx.fragment.app.Fragment, superFunc: Function): void {
superFunc.call(fragment);

View File

@ -476,6 +476,7 @@ export interface AndroidFragmentCallbacks {
onDestroyView(fragment: any, superFunc: Function): void;
onDestroy(fragment: any, superFunc: Function): void;
onPause(fragment: any, superFunc: Function): void;
onResume(fragment: any, superFunc: Function): void;
onStop(fragment: any, superFunc: Function): void;
toStringOverride(fragment: any, superFunc: Function): string;
}