mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Disable recycling, refactoring & fixes (#4705)
* Added tests for native view recycling Disabled android native view recycling Move toString from view-common to view-base Fix crash on application restore and navigation back on API26 Added setAsRootView method Added missing logo into perf-tests/recycling app * additional fix for image-source-tests. ios is case sensitive. * Add @private to some internal properties Fix where padding is not respected when background is reset.
This commit is contained in:
@@ -144,11 +144,9 @@ export abstract class ViewBase extends Observable {
|
||||
* read-only. If you want to set out-of-band the nativeView use the setNativeView method.
|
||||
*/
|
||||
public nativeViewProtected: any;
|
||||
public recycleNativeView: "always" | "never" | "auto";
|
||||
|
||||
public nativeView: any;
|
||||
public bindingContext: any;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the name of the constructor function for this instance. E.g. for a Button class this will return "Button".
|
||||
*/
|
||||
@@ -306,6 +304,14 @@ export abstract class ViewBase extends Observable {
|
||||
public ensureDomNode();
|
||||
|
||||
//@private
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public recycleNativeView: "always" | "never" | "auto";
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public _isPaddingRelative: boolean;
|
||||
public _styleScope: any;
|
||||
|
||||
/**
|
||||
@@ -321,6 +327,10 @@ export abstract class ViewBase extends Observable {
|
||||
* Allow multiple updates to be performed on the instance at once.
|
||||
*/
|
||||
public _batchUpdate<T>(callback: () => T): T;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_setupAsRootView(context: any): void;
|
||||
//@endprivate
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from "../../la
|
||||
import { KeyframeAnimation } from "../../animation/keyframe-animation";
|
||||
|
||||
// Types.
|
||||
import { Source } from "../../../utils/debug";
|
||||
import { Property, CssProperty, CssAnimationProperty, InheritedProperty, Style, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, resetCSSProperties, initNativeView, resetNativeView } from "../properties";
|
||||
import { Binding, BindingOptions, Observable, WrappedValue, PropertyChangeData, traceEnabled, traceWrite, traceCategories, traceNotifyEvent } from "../bindable";
|
||||
import { isIOS, isAndroid } from "../../../platform";
|
||||
@@ -94,40 +95,40 @@ export function eachDescendant(view: ViewBaseDefinition, callback: (child: ViewB
|
||||
|
||||
let viewIdCounter = 1;
|
||||
|
||||
const contextMap = new WeakMap<Object, Map<string, WeakRef<Object>[]>>();
|
||||
// const contextMap = new WeakMap<Object, Map<string, WeakRef<Object>[]>>();
|
||||
|
||||
function getNativeView(context: Object, typeName: string): Object {
|
||||
let typeMap = contextMap.get(context);
|
||||
if (!typeMap) {
|
||||
typeMap = new Map<string, WeakRef<Object>[]>();
|
||||
contextMap.set(context, typeMap);
|
||||
return undefined;
|
||||
}
|
||||
// function getNativeView(context: Object, typeName: string): Object {
|
||||
// let typeMap = contextMap.get(context);
|
||||
// if (!typeMap) {
|
||||
// typeMap = new Map<string, WeakRef<Object>[]>();
|
||||
// contextMap.set(context, typeMap);
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
const array = typeMap.get(typeName);
|
||||
if (array) {
|
||||
let nativeView;
|
||||
while (array.length > 0) {
|
||||
const weakRef = array.pop();
|
||||
nativeView = weakRef.get();
|
||||
if (nativeView) {
|
||||
return nativeView;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
// const array = typeMap.get(typeName);
|
||||
// if (array) {
|
||||
// let nativeView;
|
||||
// while (array.length > 0) {
|
||||
// const weakRef = array.pop();
|
||||
// nativeView = weakRef.get();
|
||||
// if (nativeView) {
|
||||
// return nativeView;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
function putNativeView(context: Object, view: ViewBase): void {
|
||||
const typeMap = contextMap.get(context);
|
||||
const typeName = view.typeName;
|
||||
let list = typeMap.get(typeName);
|
||||
if (!list) {
|
||||
list = [];
|
||||
typeMap.set(typeName, list);
|
||||
}
|
||||
list.push(new WeakRef(view.nativeViewProtected));
|
||||
}
|
||||
// function putNativeView(context: Object, view: ViewBase): void {
|
||||
// const typeMap = contextMap.get(context);
|
||||
// const typeName = view.typeName;
|
||||
// let list = typeMap.get(typeName);
|
||||
// if (!list) {
|
||||
// list = [];
|
||||
// typeMap.set(typeName, list);
|
||||
// }
|
||||
// list.push(new WeakRef(view.nativeViewProtected));
|
||||
// }
|
||||
|
||||
export abstract class ViewBase extends Observable implements ViewBaseDefinition {
|
||||
public static loadedEvent = "loaded";
|
||||
@@ -141,7 +142,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
private _visualState: string;
|
||||
private _inlineStyleSelector: SelectorCore;
|
||||
private __nativeView: any;
|
||||
private _disableNativeViewRecycling: boolean;
|
||||
// private _disableNativeViewRecycling: boolean;
|
||||
public domNode: DOMNode;
|
||||
|
||||
public recycleNativeView: "always" | "never" | "auto";
|
||||
@@ -204,7 +205,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
public _defaultPaddingRight: number;
|
||||
public _defaultPaddingBottom: number;
|
||||
public _defaultPaddingLeft: number;
|
||||
private _isPaddingRelative: boolean;
|
||||
public _isPaddingRelative: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -213,7 +214,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
get nativeView(): any {
|
||||
this._disableNativeViewRecycling = true;
|
||||
// this._disableNativeViewRecycling = true;
|
||||
return this.nativeViewProtected;
|
||||
}
|
||||
|
||||
@@ -230,7 +231,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
get android(): any {
|
||||
this._disableNativeViewRecycling = true;
|
||||
// this._disableNativeViewRecycling = true;
|
||||
return this._androidView;
|
||||
}
|
||||
|
||||
@@ -670,25 +671,29 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
private resetNativeViewInternal(): void {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView && isAndroid) {
|
||||
const recycle = this.recycleNativeView;
|
||||
if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
resetNativeView(this);
|
||||
if (this._isPaddingRelative) {
|
||||
nativeView.setPaddingRelative(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
} else {
|
||||
nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
}
|
||||
this.resetNativeView();
|
||||
}
|
||||
}
|
||||
// const nativeView = this.nativeViewProtected;
|
||||
// if (nativeView && isAndroid) {
|
||||
// const recycle = this.recycleNativeView;
|
||||
// if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
// resetNativeView(this);
|
||||
// if (this._isPaddingRelative) {
|
||||
// nativeView.setPaddingRelative(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
// } else {
|
||||
// nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
// }
|
||||
// this.resetNativeView();
|
||||
// }
|
||||
// }
|
||||
|
||||
if (this._cssState) {
|
||||
this._cancelAllAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
_setupAsRootView(context: any): void {
|
||||
this._setupUI(context);
|
||||
}
|
||||
|
||||
@profile
|
||||
public _setupUI(context: android.content.Context, atIndex?: number, parentIsLoaded?: boolean) {
|
||||
|
||||
@@ -706,10 +711,10 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
let nativeView;
|
||||
if (isAndroid) {
|
||||
const recycle = this.recycleNativeView;
|
||||
if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
nativeView = <android.view.View>getNativeView(context, this.typeName);
|
||||
}
|
||||
// const recycle = this.recycleNativeView;
|
||||
// if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
// nativeView = <android.view.View>getNativeView(context, this.typeName);
|
||||
// }
|
||||
|
||||
if (!nativeView) {
|
||||
nativeView = <android.view.View>this.createNativeView();
|
||||
@@ -790,15 +795,15 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
@profile
|
||||
public _tearDownUI(force?: boolean) {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._tearDownUI(${force})`, traceCategories.VisualTreeEvents);
|
||||
}
|
||||
|
||||
// No context means we are already teared down.
|
||||
if (!this._context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._tearDownUI(${force})`, traceCategories.VisualTreeEvents);
|
||||
}
|
||||
|
||||
this.resetNativeViewInternal();
|
||||
|
||||
this.eachChild((child) => {
|
||||
@@ -810,18 +815,24 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
this.parent._removeViewFromNativeVisualTree(this);
|
||||
}
|
||||
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView && isAndroid) {
|
||||
const recycle = this.recycleNativeView;
|
||||
if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
// const nativeParent = isAndroid ? (<android.view.View>nativeView).getParent() : (<UIView>nativeView).superview;
|
||||
const nativeParent = (<android.view.View>nativeView).getParent();
|
||||
const animation = (<android.view.View>nativeView).getAnimation();
|
||||
if (!nativeParent && !animation) {
|
||||
putNativeView(this._context, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
// const nativeView = this.nativeViewProtected;
|
||||
// if (nativeView && isAndroid) {
|
||||
// const recycle = this.recycleNativeView;
|
||||
// let shouldRecycle = false;
|
||||
// if (recycle === "always") {
|
||||
// shouldRecycle = true;
|
||||
// } else if (recycle === "auto" && !this._disableNativeViewRecycling) {
|
||||
// const propertiesSet = Object.getOwnPropertySymbols(this).length + Object.getOwnPropertySymbols(this.style).length / 2;
|
||||
// shouldRecycle = propertiesSet <= this.recyclePropertyCounter;
|
||||
// }
|
||||
|
||||
// // const nativeParent = isAndroid ? (<android.view.View>nativeView).getParent() : (<UIView>nativeView).superview;
|
||||
// const nativeParent = (<android.view.View>nativeView).getParent();
|
||||
// const animation = (<android.view.View>nativeView).getAnimation();
|
||||
// if (shouldRecycle && !nativeParent && !animation) {
|
||||
// putNativeView(this._context, this);
|
||||
// }
|
||||
// }
|
||||
|
||||
this.disposeNativeView();
|
||||
|
||||
@@ -941,6 +952,21 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
let str = this.typeName;
|
||||
if (this.id) {
|
||||
str += `<${this.id}>`;
|
||||
} else {
|
||||
str += `(${this._domId})`;
|
||||
}
|
||||
let source = Source.get(this);
|
||||
if (source) {
|
||||
str += `@${source};`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
ViewBase.prototype.isCollapsed = false;
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
import { View as ViewDefinition, Point, Size, Color, dip } from ".";
|
||||
import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties";
|
||||
|
||||
// Types.
|
||||
import { Source } from "../../../utils/debug";
|
||||
|
||||
import {
|
||||
ViewBase, Property, booleanConverter, EventData, layout,
|
||||
getEventOrGestureName, traceEnabled, traceWrite, traceCategories
|
||||
@@ -747,21 +744,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
super.resetNativeView();
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
let str = this.typeName;
|
||||
if (this.id) {
|
||||
str += `<${this.id}>`;
|
||||
} else {
|
||||
str += `(${this._domId})`;
|
||||
}
|
||||
let source = Source.get(this);
|
||||
if (source) {
|
||||
str += `@${source};`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public _setNativeViewFrame(nativeView: any, frame: any) {
|
||||
//
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { CacheLayerType } from "../../../utils/utils";
|
||||
import { Background, ad as androidBackground } from "../../styling/background";
|
||||
import {
|
||||
ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty,
|
||||
traceEnabled, traceWrite, traceCategories, traceNotifyEvent
|
||||
traceEnabled, traceWrite, traceCategories, traceNotifyEvent,
|
||||
paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty
|
||||
} from "./view-common";
|
||||
|
||||
import {
|
||||
@@ -486,7 +487,18 @@ export class View extends ViewCommon {
|
||||
} else {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
org.nativescript.widgets.ViewHelper.setBackground(nativeView, value);
|
||||
nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
|
||||
const style = this.style;
|
||||
const paddingTop = paddingTopProperty.isSet(style) ? this.effectivePaddingTop : this._defaultPaddingTop;
|
||||
const paddingRight = paddingRightProperty.isSet(style) ? this.effectivePaddingRight : this._defaultPaddingRight;
|
||||
const paddingBottom = paddingBottomProperty.isSet(style) ? this.effectivePaddingBottom : this._defaultPaddingBottom;
|
||||
const paddingLeft = paddingLeftProperty.isSet(style) ? this.effectivePaddingLeft : this._defaultPaddingLeft;
|
||||
|
||||
if (this._isPaddingRelative) {
|
||||
nativeView.setPaddingRelative(paddingLeft, paddingTop, paddingRight, paddingBottom);
|
||||
} else {
|
||||
nativeView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
|
||||
}
|
||||
|
||||
(<any>nativeView).background = undefined;
|
||||
const cache = <CacheLayerType><any>nativeView;
|
||||
|
||||
@@ -334,6 +334,22 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
this._updateActionBar();
|
||||
}
|
||||
|
||||
public _findEntryForTag(fragmentTag: string): BackstackEntry {
|
||||
let entry: BackstackEntry;
|
||||
if (this._currentEntry && this._currentEntry.fragmentTag === fragmentTag) {
|
||||
entry = this._currentEntry;
|
||||
} else {
|
||||
entry = this._backStack.find((value) => value.fragmentTag === fragmentTag);
|
||||
// on API 26 fragments are recreated lazily after activity is destroyed.
|
||||
if (!entry) {
|
||||
const navigationItem = this._navigationQueue.find((value) => value.entry.fragmentTag === fragmentTag);
|
||||
entry = navigationItem ? navigationItem.entry : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public navigationQueueIsEmpty(): boolean {
|
||||
return this._navigationQueue.length === 0;
|
||||
}
|
||||
|
||||
@@ -419,13 +419,7 @@ function findPageForFragment(fragment: android.app.Fragment, frame: Frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
let entry: BackstackEntry;
|
||||
if (frame._currentEntry && frame._currentEntry.fragmentTag === fragmentTag) {
|
||||
entry = frame._currentEntry;
|
||||
} else {
|
||||
entry = frame.backStack.find((value) => value.fragmentTag === fragmentTag);
|
||||
}
|
||||
|
||||
const entry = frame._findEntryForTag(fragmentTag);
|
||||
const page = entry ? entry.resolvedPage : undefined;
|
||||
if (page) {
|
||||
const callbacks: FragmentCallbacksImplementation = fragment[CALLBACKS];
|
||||
@@ -668,7 +662,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
||||
this._rootView = rootView;
|
||||
|
||||
// Initialize native visual tree;
|
||||
rootView._setupUI(activity);
|
||||
rootView._setupAsRootView(activity);
|
||||
activity.setContentView(rootView.nativeViewProtected, new org.nativescript.widgets.CommonLayoutParams());
|
||||
// frameId is negative w
|
||||
if (frame) {
|
||||
|
||||
4
tns-core-modules/ui/frame/frame.d.ts
vendored
4
tns-core-modules/ui/frame/frame.d.ts
vendored
@@ -132,6 +132,10 @@ export class Frame extends View {
|
||||
* @private
|
||||
*/
|
||||
_getNavBarVisible(page: Page): boolean;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_findEntryForTag(fragmentTag: string): BackstackEntry;
|
||||
//@endprivate
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,8 +20,6 @@ const DELEGATE = "_delegate";
|
||||
|
||||
let navDepth = -1;
|
||||
|
||||
const FRAME_CONTEXT = {};
|
||||
|
||||
export class Frame extends FrameBase {
|
||||
private _ios: iOSFrame;
|
||||
private _paramToNavigate: any;
|
||||
@@ -35,13 +33,6 @@ export class Frame extends FrameBase {
|
||||
public _bottom: number;
|
||||
public _isInitialNavigation: boolean = true;
|
||||
|
||||
public get _context(): any {
|
||||
return FRAME_CONTEXT;
|
||||
}
|
||||
public set _context(value: any) {
|
||||
throw new Error("Frame _context is readonly");
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._ios = new iOSFrame(this);
|
||||
@@ -255,10 +246,6 @@ export class Frame extends FrameBase {
|
||||
return this._ios;
|
||||
}
|
||||
|
||||
// get nativeView(): any {
|
||||
// return this._ios.controller.view;
|
||||
// }
|
||||
|
||||
public static get defaultAnimatedNavigation(): boolean {
|
||||
return FrameBase.defaultAnimatedNavigation;
|
||||
}
|
||||
@@ -495,10 +482,10 @@ class UINavigationControllerImpl extends UINavigationController {
|
||||
}
|
||||
|
||||
@profile
|
||||
public viewDidLoad(): void {
|
||||
super.viewDidLoad();
|
||||
public viewWillAppear(animated: boolean): void {
|
||||
super.viewWillAppear(animated);
|
||||
let owner = this._owner.get();
|
||||
if (owner) {
|
||||
if (owner && (!owner.isLoaded && !owner.parent)) {
|
||||
owner.onLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user