From 7986e479cdfbbe3fe7e030d65a7cd2650626500e Mon Sep 17 00:00:00 2001 From: Panayot Cankov Date: Fri, 12 May 2017 11:07:30 +0300 Subject: [PATCH] Performance improvements after profiling the android flexbox example --- tns-core-modules/ui/core/bindable/bindable.ts | 39 ++++++++++------- tns-core-modules/ui/image/image.android.ts | 11 +++-- tns-core-modules/ui/label/label.android.ts | 7 +++- .../flexbox-layout/flexbox-layout.android.ts | 42 ++++++++++++------- 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/tns-core-modules/ui/core/bindable/bindable.ts b/tns-core-modules/ui/core/bindable/bindable.ts index bdcba2ccc..2b1552c43 100644 --- a/tns-core-modules/ui/core/bindable/bindable.ts +++ b/tns-core-modules/ui/core/bindable/bindable.ts @@ -24,26 +24,33 @@ const contextKey = "context"; const paramsRegex = /\[\s*(['"])*(\w*)\1\s*\]/; const bc = bindingConstants; const emptyArray = []; +const propertiesCache = {}; function getProperties(property: string): Array { - let result: Array = emptyArray; - if (property) { - // first replace all '$parents[..]' with a safe string - // second removes all ] since they are not important for property access and not needed - // then split properties either on '.' or '[' - const parentsMatches = property.match(parentsRegex); - result = property.replace(parentsRegex, "parentsMatch") - .replace(/\]/g, "") - .split(/\.|\[/); - - let parentsMatchesCounter = 0; - for (let i = 0, resultLength = result.length; i < resultLength; i++) { - if (result[i] === "parentsMatch") { - result[i] = parentsMatches[parentsMatchesCounter++]; - } - } + if (!property) { + return emptyArray; } + let result: Array = propertiesCache[property]; + if (result) { + return result; + } + + // first replace all '$parents[..]' with a safe string + // second removes all ] since they are not important for property access and not needed + // then split properties either on '.' or '[' + const parentsMatches = property.match(parentsRegex); + result = property.replace(parentsRegex, "parentsMatch") + .replace(/\]/g, "") + .split(/\.|\[/); + + let parentsMatchesCounter = 0; + for (let i = 0, resultLength = result.length; i < resultLength; i++) { + if (result[i] === "parentsMatch") { + result[i] = parentsMatches[parentsMatchesCounter++]; + } + } + propertiesCache[property] = result; return result; } diff --git a/tns-core-modules/ui/image/image.android.ts b/tns-core-modules/ui/image/image.android.ts index 057781555..6b4feab41 100644 --- a/tns-core-modules/ui/image/image.android.ts +++ b/tns-core-modules/ui/image/image.android.ts @@ -2,13 +2,15 @@ ImageSource, ImageBase, stretchProperty, imageSourceProperty, srcProperty, tintColorProperty, Color, isDataURI, isFileOrResourcePath, RESOURCE_PREFIX } from "./image-common"; -import { path, knownFolders } from "../../file-system"; +import { knownFolders } from "../../file-system"; export * from "./image-common"; const FILE_PREFIX = "file:///"; const ASYNC = "async"; +let AndroidImageView: typeof org.nativescript.widgets.ImageView; + interface ImageLoadedListener { new (owner: Image): org.nativescript.widgets.image.Worker.OnImageLoadedListener; } @@ -45,9 +47,12 @@ export class Image extends ImageBase { public useCache = true; public createNativeView() { + if (!AndroidImageView) { + AndroidImageView = org.nativescript.widgets.ImageView; + } initializeImageLoadedListener(); - const imageView = new org.nativescript.widgets.ImageView(this._context); + const imageView = new AndroidImageView(this._context); const listener = new ImageLoadedListener(this); imageView.setImageLoadedListener(listener); (imageView).listener = listener; @@ -92,7 +97,7 @@ export class Image extends ImageBase { } else { let fileName = value; if (fileName.indexOf("~/") === 0) { - fileName = path.join(knownFolders.currentApp().path, fileName.replace("~/", "")); + fileName = knownFolders.currentApp().path + "/" + fileName.replace("~/", ""); } imageView.setUri(FILE_PREFIX + fileName, this.decodeWidth, this.decodeHeight, this.useCache, async); diff --git a/tns-core-modules/ui/label/label.android.ts b/tns-core-modules/ui/label/label.android.ts index 6d7df7200..0623bcc2d 100644 --- a/tns-core-modules/ui/label/label.android.ts +++ b/tns-core-modules/ui/label/label.android.ts @@ -3,6 +3,8 @@ import { TextBase, WhiteSpace, whiteSpaceProperty } from "../text-base"; export * from "../text-base"; +let TextView: typeof android.widget.TextView; + export class Label extends TextBase implements LabelDefinition { nativeView: android.widget.TextView; @@ -14,7 +16,10 @@ export class Label extends TextBase implements LabelDefinition { } public createNativeView() { - return new android.widget.TextView(this._context); + if (!TextView) { + TextView = android.widget.TextView; + } + return new TextView(this._context); } public initNativeView(): void { diff --git a/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout.android.ts b/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout.android.ts index 787bdcc51..62be2df21 100644 --- a/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout.android.ts +++ b/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout.android.ts @@ -12,11 +12,14 @@ import { export * from "./flexbox-layout-common"; +let widgetFlexboxLayout: typeof org.nativescript.widgets.FlexboxLayout; +let widgetLayoutParams: typeof org.nativescript.widgets.FlexboxLayout.LayoutParams; + function makeNativeSetter(setter: (lp: org.nativescript.widgets.FlexboxLayout.LayoutParams, value: T) => void) { return function(this: View, value: T) { const nativeView: android.view.View = this.nativeView; - const lp = nativeView.getLayoutParams() || new org.nativescript.widgets.FlexboxLayout.LayoutParams(); - if (lp instanceof org.nativescript.widgets.FlexboxLayout.LayoutParams) { + const lp = nativeView.getLayoutParams() || new widgetLayoutParams(); + if (lp instanceof widgetLayoutParams) { setter(lp, value); nativeView.setLayoutParams(lp); } @@ -80,7 +83,11 @@ export class FlexboxLayout extends FlexboxLayoutBase { nativeView: org.nativescript.widgets.FlexboxLayout; public createNativeView() { - return new org.nativescript.widgets.FlexboxLayout(this._context); + if (!widgetFlexboxLayout) { + widgetFlexboxLayout = org.nativescript.widgets.FlexboxLayout; + widgetLayoutParams = widgetFlexboxLayout.LayoutParams; + } + return new widgetFlexboxLayout(this._context); } public disposeNativeView() { @@ -127,29 +134,32 @@ export class FlexboxLayout extends FlexboxLayoutBase { super._updateNativeLayoutParams(child); const lp = child.nativeView.getLayoutParams(); - lp.order = child.order; - lp.flexGrow = child.flexGrow; - lp.flexShrink = child.flexShrink; - lp.wrapBefore = child.flexWrapBefore; - lp.alignSelf = alignSelfMap[child.alignSelf]; + const style = child.style; + lp.order = style.order; + lp.flexGrow = style.flexGrow; + lp.flexShrink = style.flexShrink; + lp.wrapBefore = style.flexWrapBefore; + lp.alignSelf = alignSelfMap[style.alignSelf]; child.nativeView.setLayoutParams(lp); } public _setChildMinWidthNative(child: View): void { child._setMinWidthNative(0); - const lp = child.nativeView.getLayoutParams(); - if (lp instanceof org.nativescript.widgets.FlexboxLayout.LayoutParams) { - lp.minWidth = Length.toDevicePixels(child.minWidth, 0); - child.nativeView.setLayoutParams(lp); + const nativeView = child.nativeView; + const lp = nativeView.getLayoutParams(); + if (lp instanceof widgetLayoutParams) { + lp.minWidth = Length.toDevicePixels(child.style.minWidth, 0); + nativeView.setLayoutParams(lp); } } public _setChildMinHeightNative(child: View): void { child._setMinHeightNative(0); - const lp = child.nativeView.getLayoutParams(); - if (lp instanceof org.nativescript.widgets.FlexboxLayout.LayoutParams) { - lp.minHeight = Length.toDevicePixels(child.minHeight, 0); - child.nativeView.setLayoutParams(lp); + const nativeView = child.nativeView; + const lp = nativeView.getLayoutParams(); + if (lp instanceof widgetLayoutParams) { + lp.minHeight = Length.toDevicePixels(child.style.minHeight, 0); + nativeView.setLayoutParams(lp); } } } \ No newline at end of file