Fix crash with nested frames navigation when aactivity is recreated. We now check if frame native view is atached to window before running navigation.

Livesync now recreates the main page instead of calling frame.navigate
This commit is contained in:
Hristo Hristov
2018-01-15 18:07:20 +02:00
parent 3f2f5f41f0
commit 9dd3e1a807
4 changed files with 70 additions and 26 deletions

View File

@ -934,6 +934,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
public _redrawNativeBackground(value: any): void { public _redrawNativeBackground(value: any): void {
// //
} }
_onAttachedToWindow(): void {
//
}
_onDetachedFromWindow(): void {
//
}
} }
export const automationTextProperty = new Property<ViewCommon, string>({ name: "automationText" }); export const automationTextProperty = new Property<ViewCommon, string>({ name: "automationText" });

View File

@ -164,6 +164,7 @@ function initializeDialogFragment() {
const window = this.getDialog().getWindow(); const window = this.getDialog().getWindow();
const length = android.view.ViewGroup.LayoutParams.MATCH_PARENT; const length = android.view.ViewGroup.LayoutParams.MATCH_PARENT;
window.setLayout(length, length); window.setLayout(length, length);
// This removes the default backgroundDrawable so there are no margins.
window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.WHITE)); window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.WHITE));
} }

View File

@ -666,6 +666,16 @@ export abstract class View extends ViewBase {
* @param css * @param css
*/ */
_updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void; _updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void;
/**
* Called in android when native view is attached to window.
*/
_onAttachedToWindow(): void;
/**
* Called in android when native view is dettached from window.
*/
_onDetachedFromWindow(): void;
//@endprivate //@endprivate
/** /**

View File

@ -28,6 +28,8 @@ const INTENT_EXTRA = "com.tns.activity";
const FRAMEID = "_frameId"; const FRAMEID = "_frameId";
const CALLBACKS = "_callbacks"; const CALLBACKS = "_callbacks";
const ownerSymbol = Symbol("_owner");
let navDepth = -1; let navDepth = -1;
let fragmentId = -1; let fragmentId = -1;
export let moduleLoaded: boolean; export let moduleLoaded: boolean;
@ -38,36 +40,41 @@ if (global && global.__inspector) {
devtools.attachDOMInspectorCommandCallbacks(global.__inspector); devtools.attachDOMInspectorCommandCallbacks(global.__inspector);
} }
export let attachStateChangeListener: android.view.View.OnAttachStateChangeListener;
function getAttachListener(): android.view.View.OnAttachStateChangeListener {
if (!attachStateChangeListener) {
@Interfaces([android.view.View.OnAttachStateChangeListener])
class AttachListener extends java.lang.Object implements android.view.View.OnAttachStateChangeListener {
constructor() {
super();
return global.__native(this);
}
onViewAttachedToWindow(view: android.view.View): void {
const owner: View = view[ownerSymbol];
if (owner) {
owner._onAttachedToWindow();
}
}
onViewDetachedFromWindow(view: android.view.View): void {
const owner: View = view[ownerSymbol];
if (owner) {
owner._onDetachedFromWindow();
}
}
}
attachStateChangeListener = new AttachListener();
}
return attachStateChangeListener;
}
export function reloadPage(): void { export function reloadPage(): void {
const frame = topmost(); // Delete previously cached root view in order to recreate it.
if (frame) { resetActivityContent(application.android.foregroundActivity);
if (frame.currentPage && frame.currentPage.modal) {
frame.currentPage.modal.closeModal();
}
const currentEntry = frame._currentEntry.entry;
const newEntry: NavigationEntry = {
animated: false,
clearHistory: true,
context: currentEntry.context,
create: currentEntry.create,
moduleName: currentEntry.moduleName,
backstackVisible: currentEntry.backstackVisible
}
// If create returns the same page instance we can't recreate it.
// Instead of navigation set activity content.
// This could happen if current page was set in XML as a Page instance.
if (newEntry.create) {
const page = newEntry.create();
if (page === frame.currentPage) {
resetActivityContent(frame.android.activity);
return;
}
}
frame.navigate(newEntry);
}
} }
// attach on global, so it can be overwritten in NativeScript Angular // attach on global, so it can be overwritten in NativeScript Angular
@ -78,6 +85,7 @@ export class Frame extends FrameBase {
private _delayedNavigationEntry: BackstackEntry; private _delayedNavigationEntry: BackstackEntry;
private _containerViewId: number = -1; private _containerViewId: number = -1;
private _tearDownPending = false; private _tearDownPending = false;
private _attachedToWindow = false;
public _isBack: boolean = true; public _isBack: boolean = true;
constructor() { constructor() {
@ -107,13 +115,24 @@ export class Frame extends FrameBase {
return this._android; return this._android;
} }
_onAttachedToWindow(): void {
super._onAttachedToWindow();
this._attachedToWindow = true;
this._processNextNavigationEntry();
}
_onDetachedFromWindow(): void {
super._onDetachedFromWindow();
this._attachedToWindow = false;
}
protected _processNextNavigationEntry(): void { protected _processNextNavigationEntry(): void {
// In case activity was destroyed because of back button pressed (e.g. app exit) // In case activity was destroyed because of back button pressed (e.g. app exit)
// and application is restored from recent apps, current fragment isn't recreated. // and application is restored from recent apps, current fragment isn't recreated.
// In this case call _navigateCore in order to recreate the current fragment. // In this case call _navigateCore in order to recreate the current fragment.
// Don't call navigate because it will fire navigation events. // Don't call navigate because it will fire navigation events.
// As JS instances are alive it is already done for the current page. // As JS instances are alive it is already done for the current page.
if (!this.isLoaded) { if (!this.isLoaded || !this._attachedToWindow) {
return; return;
} }
@ -328,6 +347,9 @@ export class Frame extends FrameBase {
public initNativeView(): void { public initNativeView(): void {
super.initNativeView(); super.initNativeView();
const listener = getAttachListener();
this.nativeViewProtected.addOnAttachStateChangeListener(listener);
this.nativeViewProtected[ownerSymbol] = this;
this._android.rootViewGroup = this.nativeViewProtected; this._android.rootViewGroup = this.nativeViewProtected;
if (this._containerViewId < 0) { if (this._containerViewId < 0) {
this._containerViewId = android.view.View.generateViewId(); this._containerViewId = android.view.View.generateViewId();
@ -336,6 +358,9 @@ export class Frame extends FrameBase {
} }
public disposeNativeView() { public disposeNativeView() {
const listener = getAttachListener();
this.nativeViewProtected.removeOnAttachStateChangeListener(listener);
this.nativeViewProtected[ownerSymbol] = null;
this._tearDownPending = !!this._executingEntry; this._tearDownPending = !!this._executingEntry;
const current = this._currentEntry; const current = this._currentEntry;