Added @profile on several key methods in the Android lifecycle, refactored by extracting into methods a little (#4685)

This commit is contained in:
Panayot Cankov
2017-08-24 13:10:53 +03:00
committed by GitHub
parent 7b364613da
commit 3a447b6f3f
8 changed files with 210 additions and 146 deletions

View File

@ -180,9 +180,7 @@ global.__onLiveSync = function () {
};
function initLifecycleCallbacks() {
// TODO: Verify whether the logic for triggerring application-wide events based on Activity callbacks is working properly
const lifecycleCallbacks = new android.app.Application.ActivityLifecycleCallbacks({
onActivityCreated: profile("onActivityCreated", function (activity: android.app.Activity, savedInstanceState: android.os.Bundle) {
const setThemeOnLaunch = profile("setThemeOnLaunch", (activity: android.app.Activity) => {
// Set app theme after launch screen was used during startup
const activityInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), android.content.pm.PackageManager.GET_META_DATA);
if (activityInfo.metaData) {
@ -191,14 +189,13 @@ function initLifecycleCallbacks() {
activity.setTheme(setThemeOnLaunch);
}
}
});
if (!androidApp.startActivity) {
androidApp.startActivity = activity;
}
const notifyActivityCreated = profile("notifyActivityCreated", function(activity: android.app.Activity, savedInstanceState: android.os.Bundle) {
androidApp.notify(<AndroidActivityBundleEventData>{ eventName: ActivityCreated, object: androidApp, activity, bundle: savedInstanceState });
});
if (hasListeners(displayedEvent)) {
const subscribeForGlobalLayout = profile("subscribeForGlobalLayout", function(activity: android.app.Activity) {
const rootView = activity.getWindow().getDecorView().getRootView();
let onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({
onGlobalLayout() {
@ -208,6 +205,20 @@ function initLifecycleCallbacks() {
}
});
rootView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
});
const lifecycleCallbacks = new android.app.Application.ActivityLifecycleCallbacks({
onActivityCreated: profile("onActivityCreated", function (activity: android.app.Activity, savedInstanceState: android.os.Bundle) {
setThemeOnLaunch(activity);
if (!androidApp.startActivity) {
androidApp.startActivity = activity;
}
notifyActivityCreated(activity, savedInstanceState);
if (hasListeners(displayedEvent)) {
subscribeForGlobalLayout(activity);
}
}),

View File

@ -39,7 +39,10 @@
"snapshot": {
"android": {
"tns-java-classes": {
"modules": ["ui/frame/activity", "ui/frame/fragment"]
"modules": [
"ui/frame/activity",
"ui/frame/fragment"
]
}
}
}

View File

@ -10,6 +10,7 @@ import { isString, isDefined } from "../../utils/types";
import { ComponentModule, setPropertyValue, getComponentModule } from "./component-builder";
import { platformNames, device } from "../../platform";
import { resolveFileName } from "../../file-system/file-name-resolver";
import { profile } from "tns-core-modules/profiling";
import * as traceModule from "../../trace";
const ios = platformNames.ios.toLowerCase();
@ -445,28 +446,28 @@ namespace xml2ui {
this._state = TemplateParser.State.FINISHED;
if (this._setTemplateProperty && this._templateProperty.name in this._templateProperty.parent.component) {
let template = this._build();
let template = this.buildTemplate();
this._templateProperty.parent.component[this._templateProperty.name] = template;
}
}
}
public _build(): Template {
public buildTemplate(): Template {
var context = this._context;
var errorFormat = this._templateProperty.errorFormat;
var sourceTracker = this._templateProperty.sourceTracker;
var template: Template = () => {
var template: Template = profile("Template()", () => {
var start: xml2ui.XmlArgsReplay;
var ui: xml2ui.ComponentParser;
(start = new xml2ui.XmlArgsReplay(this._recordedXmlStream, errorFormat))
// No platform filter, it has been filtered allready
// No platform filter, it has been filtered already
.pipe(new XmlStateParser(ui = new ComponentParser(context, errorFormat, sourceTracker)));
start.replay();
return ui.rootComponentModule.component;
}
});
return template;
}
}
@ -492,7 +493,7 @@ namespace xml2ui {
for (let i = 0; i < this._childParsers.length; i++) {
templates.push({
key: this._childParsers[i]["key"],
createView: this._childParsers[i]._build()
createView: this._childParsers[i].buildTemplate()
});
}
this.templateProperty.parent.component[this.templateProperty.name] = templates;
@ -535,6 +536,22 @@ namespace xml2ui {
this.sourceTracker = sourceTracker;
}
@profile
private buildComponent(args: xml.ParserEvent): ComponentModule {
if (args.prefix && args.namespace) {
// Custom components
return loadCustomComponent(args.namespace, args.elementName, args.attributes, this.context, this.currentRootView);
} else {
// Default components
let namespace = args.namespace;
if (defaultNameSpaceMatcher.test(namespace || '')) {
//Ignore the default ...tns.xsd namespace URL
namespace = undefined;
}
return getComponentModule(args.elementName, namespace, args.attributes, this.context, this.moduleNamePath);
}
}
public parse(args: xml.ParserEvent): XmlStateConsumer {
// Get the current parent.
@ -579,20 +596,7 @@ namespace xml2ui {
} else {
var componentModule: ComponentModule;
if (args.prefix && args.namespace) {
// Custom components
componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, this.context, this.currentRootView);
} else {
// Default components
let namespace = args.namespace;
if (defaultNameSpaceMatcher.test(namespace || '')) {
//Ignore the default ...tns.xsd namespace URL
namespace = undefined;
}
componentModule = getComponentModule(args.elementName, namespace, args.attributes, this.context, this.moduleNamePath);
}
var componentModule = this.buildComponent(args);
if (componentModule) {
this.sourceTracker(componentModule.component, args.position);

View File

@ -7,6 +7,7 @@ import { isEventOrGesture } from "../../core/bindable";
import { File, path, knownFolders } from "../../../file-system";
import { getBindingOptions, bindingConstants } from "../binding-builder";
import { resolveFileName } from "../../../file-system/file-name-resolver";
import { profile } from "tns-core-modules/profiling";
import * as debugModule from "../../../utils/debug";
import * as platform from "../../../platform";
@ -24,14 +25,9 @@ const CODEFILE = "codeFile";
const CSSFILE = "cssFile";
const IMPORT = "import";
export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object, moduleNamePath?: string): ComponentModule {
const createComponentInstance = profile("createComponentInstance", (elementName: string, namespace: string): { instance: View, instanceModule: Object } => {
var instance: View;
var instanceModule: Object;
var componentModule: ComponentModule;
// Support lower-case-dashed component declaration in the XML (https://github.com/NativeScript/NativeScript/issues/309).
elementName = elementName.split("-").map(s => { return s[0].toUpperCase() + s.substring(1) }).join("");
// Get module id.
var moduleId = MODULES[elementName] || UI_PATH +
(elementName.toLowerCase().indexOf("layout") !== -1 ? "layouts/" : "") +
@ -70,7 +66,10 @@ export function getComponentModule(elementName: string, namespace: string, attri
throw new debug.ScopeError(ex, "Module '" + moduleId + "' not found for element '" + (namespace ? namespace + ":" : "") + elementName + "'.");
}
let cssApplied = false;
return { instance, instanceModule };
});
const getComponentModuleExports = profile("getComponentModuleExports", (instance: View, moduleExports: Object, attributes: Object): Object => {
if (attributes) {
if (attributes[IMPORT]) {
let importPath = attributes[IMPORT].trim();
@ -79,11 +78,10 @@ export function getComponentModule(elementName: string, namespace: string, attri
importPath = path.join(knownFolders.currentApp().path, importPath.replace("~/", ""));
}
exports = global.loadModule(importPath);
(<any>instance).exports = exports;
moduleExports = global.loadModule(importPath);
(<any>instance).exports = moduleExports;
}
// if (instance instanceof Page) {
if (attributes[CODEFILE]) {
let codeFilePath = attributes[CODEFILE].trim();
if (codeFilePath.indexOf("~/") === 0) {
@ -92,13 +90,19 @@ export function getComponentModule(elementName: string, namespace: string, attri
const codeFilePathWithExt = codeFilePath.indexOf(".js") !== -1 ? codeFilePath : `${codeFilePath}.js`;
if (File.exists(codeFilePathWithExt)) {
exports = global.loadModule(codeFilePath);
(<any>instance).exports = exports;
moduleExports = global.loadModule(codeFilePath);
(<any>instance).exports = moduleExports;
} else {
throw new Error(`Code file with path "${codeFilePathWithExt}" cannot be found!`);
}
}
}
return moduleExports;
});
const applyComponentCss = profile("applyComponentCss", (instance: View, moduleNamePath: string, attributes: Object) => {
let cssApplied = false;
if (attributes) {
if (attributes[CSSFILE] && typeof (<any>instance).addCssFile === "function") {
let cssFilePath = attributes[CSSFILE].trim();
if (cssFilePath.indexOf("~/") === 0) {
@ -111,7 +115,6 @@ export function getComponentModule(elementName: string, namespace: string, attri
throw new Error(`Css file with path "${cssFilePath}" cannot be found!`);
}
}
// }
}
if (typeof (<any>instance).addCssFile === "function") {//instance instanceof Page) {
@ -129,7 +132,9 @@ export function getComponentModule(elementName: string, namespace: string, attri
(<any>instance)._refreshCss();
}
}
});
const applyComponentAttributes = profile("applyComponentAttributes", (instance: View, instanceModule: Object, moduleExports: Object, attributes: Object) => {
if (instance && instanceModule) {
for (let attr in attributes) {
@ -157,16 +162,28 @@ export function getComponentModule(elementName: string, namespace: string, attri
}
if (subObj !== undefined && subObj !== null) {
setPropertyValue(subObj, instanceModule, exports, subPropName, attrValue);
setPropertyValue(subObj, instanceModule, moduleExports, subPropName, attrValue);
}
} else {
setPropertyValue(instance, instanceModule, exports, attr, attrValue);
setPropertyValue(instance, instanceModule, moduleExports, attr, attrValue);
}
}
}
});
export function getComponentModule(elementName: string, namespace: string, attributes: Object, moduleExports: Object, moduleNamePath?: string): ComponentModule {
// Support lower-case-dashed component declaration in the XML (https://github.com/NativeScript/NativeScript/issues/309).
elementName = elementName.split("-").map(s => { return s[0].toUpperCase() + s.substring(1) }).join("");
const { instance, instanceModule } = createComponentInstance(elementName, namespace);
moduleExports = getComponentModuleExports(instance, moduleExports, attributes);
applyComponentCss(instance, moduleNamePath, attributes);
applyComponentAttributes(instance, instanceModule, moduleExports, attributes);
var componentModule;
if (instance && instanceModule) {
componentModule = { component: instance, exports: instanceModule };
}
return componentModule;
}

View File

@ -8,6 +8,7 @@ import { resolveFileName } from "../../file-system/file-name-resolver";
import { knownFolders, path } from "../../file-system";
import { parse, loadPage } from "../builder";
import * as application from "../../application";
import { profile } from "tns-core-modules/profiling";
export { application };
@ -81,33 +82,42 @@ export function reloadPage(): void {
// attach on global, so it can be overwritten in NativeScript Angular
(<any>global).__onLiveSyncCore = reloadPage;
export function resolvePageFromEntry(entry: NavigationEntry): Page {
let page: Page;
if (entry.create) {
page = entry.create();
const entryCreatePage = profile("entry.create", (entry: NavigationEntry): Page => {
const page = entry.create();
if (!page) {
throw new Error("Failed to create Page with entry.create() function.");
}
page._refreshCss();
}
else if (entry.moduleName) {
// Current app full path.
let currentAppPath = knownFolders.currentApp().path;
//Full path of the module = current app full path + module name.
let moduleNamePath = path.join(currentAppPath, entry.moduleName);
traceWrite("frame module path: " + moduleNamePath, traceCategories.Navigation);
traceWrite("frame module module: " + entry.moduleName, traceCategories.Navigation);
return page;
});
let moduleExports;
interface PageModuleExports {
createPage?: () => Page;
}
const moduleCreatePage = profile("module.createPage", (moduleNamePath: string, moduleExports: PageModuleExports): Page => {
if (traceEnabled()) {
traceWrite("Calling createPage()", traceCategories.Navigation);
}
var page = moduleExports.createPage();
let cssFileName = resolveFileName(moduleNamePath, "css");
// If there is no cssFile only appCss will be applied at loaded.
if (cssFileName) {
page.addCssFile(cssFileName);
}
return page;
});
const loadPageModule = profile("loadPageModule", (moduleNamePath: string, entry: NavigationEntry): PageModuleExports => {
// web-pack case where developers register their page JS file manually.
if (global.moduleExists(entry.moduleName)) {
if (traceEnabled()) {
traceWrite("Loading pre-registered JS module: " + entry.moduleName, traceCategories.Navigation);
}
moduleExports = global.loadModule(entry.moduleName);
return global.loadModule(entry.moduleName);
} else {
let moduleExportsResolvedPath = resolveFileName(moduleNamePath, "js");
if (moduleExportsResolvedPath) {
@ -117,35 +127,13 @@ export function resolvePageFromEntry(entry: NavigationEntry): Page {
// Exclude extension when doing require.
moduleExportsResolvedPath = moduleExportsResolvedPath.substr(0, moduleExportsResolvedPath.length - 3)
moduleExports = global.loadModule(moduleExportsResolvedPath);
return global.loadModule(moduleExportsResolvedPath);
}
}
return null;
});
if (moduleExports && moduleExports.createPage) {
if (traceEnabled()) {
traceWrite("Calling createPage()", traceCategories.Navigation);
}
page = moduleExports.createPage();
let cssFileName = resolveFileName(moduleNamePath, "css");
// If there is no cssFile only appCss will be applied at loaded.
if (cssFileName) {
page.addCssFile(cssFileName);
}
} else {
// cssFileName is loaded inside pageFromBuilder->loadPage
page = pageFromBuilder(moduleNamePath, moduleExports);
}
if (!page) {
throw new Error("Failed to load Page from entry.moduleName: " + entry.moduleName);
}
}
return page;
}
function pageFromBuilder(moduleNamePath: string, moduleExports: any): Page {
const pageFromBuilder = profile("pageFromBuilder", (moduleNamePath: string, moduleExports: any): Page => {
let page: Page;
// Possible XML file path.
@ -165,8 +153,38 @@ function pageFromBuilder(moduleNamePath: string, moduleExports: any): Page {
// }
return page;
});
export const resolvePageFromEntry = profile("resolvePageFromEntry", (entry: NavigationEntry): Page => {
let page: Page;
if (entry.create) {
page = entryCreatePage(entry);
} else if (entry.moduleName) {
// Current app full path.
let currentAppPath = knownFolders.currentApp().path;
//Full path of the module = current app full path + module name.
const moduleNamePath = path.join(currentAppPath, entry.moduleName);
traceWrite("frame module path: " + moduleNamePath, traceCategories.Navigation);
traceWrite("frame module module: " + entry.moduleName, traceCategories.Navigation);
const moduleExports = loadPageModule(moduleNamePath, entry);
if (moduleExports && moduleExports.createPage) {
page = moduleCreatePage(moduleNamePath, moduleExports);
} else {
// cssFileName is loaded inside pageFromBuilder->loadPage
page = pageFromBuilder(moduleNamePath, moduleExports);
}
if (!page) {
throw new Error("Failed to load Page from entry.moduleName: " + entry.moduleName);
}
}
return page;
});
export interface NavigationContext {
entry: BackstackEntry;
isBackNavigation: boolean;
@ -377,6 +395,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
}
}
@profile
private performNavigation(navigationContext: NavigationContext) {
let navContext = navigationContext.entry;
@ -391,6 +410,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
this._navigateCore(navContext);
}
@profile
private performGoBack(navigationContext: NavigationContext) {
const navContext = navigationContext.entry;
this._onNavigatingTo(navContext, navigationContext.isBackNavigation);

View File

@ -610,11 +610,8 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
const app = application.android;
const intent = activity.getIntent();
const launchArgs: application.LaunchEventData = { eventName: application.launchEvent, object: app, android: intent };
application.notify(launchArgs);
let rootView = this.notifyLaunch(intent);
let frameId = -1;
let rootView = launchArgs.root;
const extras = intent.getExtras();
// We have extras when we call - new Frame().navigate();
@ -672,6 +669,13 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
activityInitialized = true;
}
@profile
private notifyLaunch(intent: android.content.Intent): View {
const launchArgs: application.LaunchEventData = { eventName: application.launchEvent, object: application.android, android: intent };
application.notify(launchArgs);
return launchArgs.root;
}
@profile
public onSaveInstanceState(activity: android.app.Activity, outState: android.os.Bundle, superFunc: Function): void {
superFunc.call(activity, outState);

View File

@ -167,6 +167,7 @@ export class PageBase extends ContentView implements PageDefinition {
};
}
@profile
public onNavigatingTo(context: any, isBackNavigation: boolean, bindingContext?: any) {
this._navigationContext = context;
@ -177,14 +178,17 @@ export class PageBase extends ContentView implements PageDefinition {
this.notify(this.createNavigatedData(PageBase.navigatingToEvent, isBackNavigation));
}
@profile
public onNavigatedTo(isBackNavigation: boolean) {
this.notify(this.createNavigatedData(PageBase.navigatedToEvent, isBackNavigation));
}
@profile
public onNavigatingFrom(isBackNavigation: boolean) {
this.notify(this.createNavigatedData(PageBase.navigatingFromEvent, isBackNavigation));
}
@profile
public onNavigatedFrom(isBackNavigation: boolean) {
this.notify(this.createNavigatedData(PageBase.navigatedFromEvent, isBackNavigation));

View File

@ -3,6 +3,7 @@ import { CacheLayerType, isDataURI, isFileOrResourcePath, layout, RESOURCE_PREFI
import { parse } from "../../css-value";
import { path, knownFolders } from "../../file-system";
import * as application from "../../application";
import { profile } from "tns-core-modules/profiling";
export * from "./background-common"
interface AndroidView {
@ -245,16 +246,16 @@ function onLivesync(args): void {
}
application.on("livesync", onLivesync);
application.android.on("activityStarted", (args) => {
application.android.on("activityStarted", profile("initImageCache", args => {
if (!imageFetcher) {
initImageCache(args.activity);
} else {
imageFetcher.initCache();
}
});
}));
application.android.on("activityStopped", (args) => {
application.android.on("activityStopped", profile("closeImageCache", args => {
if (imageFetcher) {
imageFetcher.closeCache();
}
});
}));