[ALOY-834] Android only: Alloy generates addeventlistener call before createTabGroup call causing crash on Android when <Menu> is in XML...
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Critical |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2013-09-24T18:45:59.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Alloy 1.3.0, 2013 Sprint 20 |
Components | Runtime, XML |
Labels | alloy, android, crash, menu, qe-testadded |
Reporter | Henry David Spells III |
Assignee | Tony Lukasavage |
Created | 2013-09-23T02:50:41.000+0000 |
Updated | 2013-10-14T20:44:26.000+0000 |
Description
The alloy compiler is generating an addEventListener call on a tabGroup before generating a necessary createTabGroup call. The addEventListener is generated to create the Android menus. I'm pretty sure these were calls were generated in the correct order in Alloy 1.2.0 and possibly 1.2.1.
line 48 of ScheduleGroup.js says
$.__views.ScheduleGroup.addEventListener("open", __alloyId6);
lines 56-61 of SceduleGroup.js says
$.__views.ScheduleGroup = Ti.UI.createTabGroup({
tabs: __alloyId7,
id: "ScheduleGroup",
activeTabIconTint: "yellow",
tabsBackgroundSelectedColor: "yellow"
});
Obviously this is going to crash since $.__views.ScheduleGroup is referenced in line 48 before it is initialized in line 56-61.
This XML
<Alloy>
<TabGroup id="ScheduleGroup" onOpen="doOnOpen" onFocus="doOnFocus" activeTabIconTint="yellow" tabsBackgroundSelectedColor="yellow">
<Menu id="menu" platform="android">
<MenuItem id="refreshMenuItem" title="Refresh" onClick="doRefresh" showAsAction="Ti.Android.SHOW_AS_ACTION_IF_ROOM" itemId="1" />
<MenuItem id="settingsMenuItem" title="Settings" onClick="doSettingsMenuItem" showAsAction="Ti.Android.SHOW_AS_ACTION_IF_ROOM" itemId="0" />
</Menu>
<Require src="scheduleTab" />
</TabGroup>
</Alloy>
generates
function Controller() {
function __alloyId6() {
$.__views.ScheduleGroup.removeEventListener("open", __alloyId6);
if ($.__views.ScheduleGroup.activity) $.__views.ScheduleGroup.activity.onCreateOptionsMenu = function(e) {
var __alloyId4 = {
id: "refreshMenuItem",
title: "Refresh",
showAsAction: Ti.Android.SHOW_AS_ACTION_IF_ROOM,
itemId: "1"
};
$.__views.refreshMenuItem = e.menu.add(_.pick(__alloyId4, Alloy.Android.menuItemCreateArgs));
$.__views.refreshMenuItem.applyProperties(_.omit(__alloyId4, Alloy.Android.menuItemCreateArgs));
doRefresh ? $.__views.refreshMenuItem.addEventListener("click", doRefresh) : __defers["$.__views.refreshMenuItem!click!doRefresh"] = true;
var __alloyId5 = {
id: "settingsMenuItem",
title: "Settings",
showAsAction: Ti.Android.SHOW_AS_ACTION_IF_ROOM,
itemId: "0"
};
$.__views.settingsMenuItem = e.menu.add(_.pick(__alloyId5, Alloy.Android.menuItemCreateArgs));
$.__views.settingsMenuItem.applyProperties(_.omit(__alloyId5, Alloy.Android.menuItemCreateArgs));
doSettingsMenuItem ? $.__views.settingsMenuItem.addEventListener("click", doSettingsMenuItem) : __defers["$.__views.settingsMenuItem!click!doSettingsMenuItem"] = true;
}; else {
Ti.API.warn("You attempted to attach an Android Menu to a lightweight Window");
Ti.API.warn("or other UI component which does not have an Android activity.");
Ti.API.warn("Android Menus can only be opened on TabGroups and heavyweight Windows.");
}
}
function doSettingsMenuItem() {
showHideTabGroup(tabGroup, true);
openSettingsInContainer(tabGroup.activeTab);
}
function doOnFocus() {}
function doOnOpen() {
setupAndroidMenuIcons(tabGroup);
}
function doRefresh(e) {
globalEvtMgr.fireevent("refresh", "", e);
}
require("alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments));
this.__controllerPath = "ScheduleGroup";
arguments[0] ? arguments[0]["__parentSymbol"] : null;
arguments[0] ? arguments[0]["$model"] : null;
arguments[0] ? arguments[0]["__itemTemplate"] : null;
var $ = this;
var exports = {};
var __defers = {};
$.__views.ScheduleGroup.addEventListener("open", __alloyId6);
var __alloyId7 = [];
$.__views.__alloyId8 = Alloy.createController("scheduleTab", {
id: "__alloyId8"
});
__alloyId7.push($.__views.__alloyId8.getViewEx({
recurse: true
}));
$.__views.ScheduleGroup = Ti.UI.createTabGroup({
tabs: __alloyId7,
id: "ScheduleGroup",
activeTabIconTint: "yellow",
tabsBackgroundSelectedColor: "yellow"
});
$.__views.ScheduleGroup && $.addTopLevelView($.__views.ScheduleGroup);
doOnOpen ? $.__views.ScheduleGroup.addEventListener("open", doOnOpen) : __defers["$.__views.ScheduleGroup!open!doOnOpen"] = true;
doOnFocus ? $.__views.ScheduleGroup.addEventListener("focus", doOnFocus) : __defers["$.__views.ScheduleGroup!focus!doOnFocus"] = true;
exports.destroy = function() {};
_.extend($, $.__views);
var tabGroup = $.ScheduleGroup;
Alloy.Globals.tabGroup = tabGroup;
Alloy.Globals.tabBarVisible = true;
__defers["$.__views.refreshMenuItem!click!doRefresh"] && $.__views.refreshMenuItem.addEventListener("click", doRefresh);
__defers["$.__views.settingsMenuItem!click!doSettingsMenuItem"] && $.__views.settingsMenuItem.addEventListener("click", doSettingsMenuItem);
__defers["$.__views.ScheduleGroup!open!doOnOpen"] && $.__views.ScheduleGroup.addEventListener("open", doOnOpen);
__defers["$.__views.ScheduleGroup!focus!doOnFocus"] && $.__views.ScheduleGroup.addEventListener("focus", doOnFocus);
_.extend($, exports);
}
var Alloy = require("alloy"), Backbone = Alloy.Backbone, _ = Alloy._;
module.exports = Controller;
PR: https://github.com/appcelerator/alloy/pull/245 test apps: * https://github.com/appcelerator/alloy/tree/master/test/apps/testing/ALOY-834 * https://github.com/appcelerator/alloy/tree/master/test/apps/ui/tabgroup Functional tests should be performed on both apps, with iOS and Android, and should be performed on one TiSDK greater than 3.1.0, and one TiSDK less than 3.1.0. Make sure all tests run without error. Additionally, the android tests should be able to launch the Android Menu with the menu button.
Verified fixed. TiSDK 3.2.0.v20131013140318 Alloy 1.3.0 Xcode 5 and iOS7 (device and emulator) Android Google Nexus One (4.1.2) and Android Emulator 2.3.3 Closing