{ "id": "172900", "key": "TIMOB-26758", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "20432", "name": "Release 8.0.1", "archived": false, "released": true, "releaseDate": "2019-05-15" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2019-04-03T09:26:38.000+0000", "created": "2019-01-21T12:03:59.000+0000", "priority": { "name": "Medium", "id": "3" }, "labels": [ "android", "engSchedule", "parity", "tabbedbar", "tabs" ], "versions": [ { "id": "19882", "name": "Release 8.0.0", "archived": false, "released": true, "releaseDate": "2019-03-14" } ], "issuelinks": [], "assignee": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2019-04-03T09:26:38.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "*Summary:*\r\nChanging {{Ti.UI.TabbedBar}} properties \"labels\" or \"index\" after creating the tabbed bar but before its parent window will cause a crash.\r\n\r\nThis is a parity issue. iOS allows these properties to be changed dynamically.\r\n\r\n*Steps to reproduce:*\r\n# Build and run the below code on Android.\r\n# On app startup, notice it crashes.\r\n\r\n{code:javascript}\r\nvar window = Ti.UI.createWindow();\r\nvar tabbedBar = Ti.UI.createTabbedBar();\r\ntabbedBar.labels = [\"One\", \"Two\", \"Three\"];\r\ntabbedBar.index = 1;\r\nTi.API.info(\"@@@ TabbedBar.index: \" + tabbedBar.index);\r\nwindow.add(tabbedBar);\r\nwindow.open();\r\n{code}\r\n\r\n*Result:*\r\nWill get the below error when setting the \"labels\" property.\r\n{code}\r\n[ERROR] TiExceptionHandler: Error: Attempt to invoke virtual method 'void ti.modules.titanium.ui.widget.TiUITabbedBar.setNewLabels()' on a null object reference\r\n{code}\r\n\r\nWill get the below error when setting the \"index\" property.\r\n{code}\r\n[ERROR] TiExceptionHandler: Error: Attempt to invoke virtual method 'void ti.modules.titanium.ui.widget.TiUITabbedBar.setSelectedIndex(int)' on a null object reference\r\n{code}\r\n\r\n*Work-Around:*\r\nMove all property {{TabbedBar}} property changing code to the window's open event handler.\r\n\r\nOr avoid setting these property dynamically and assign them once via its creation properties.\r\n{code:javascript}\r\nvar window = Ti.UI.createWindow();\r\nvar tabbedBar = Ti.UI.createTabbedBar({\r\n\tlabels: [\"One\", \"Two\", \"Three\"],\r\n\tindex: 1,\r\n});\r\nwindow.add(tabbedBar);\r\nwindow.open();\r\n{code}\r\n", "attachment": [ { "id": "66331", "filename": "20190320_113615_2.mp4", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2019-03-20T10:44:57.000+0000", "size": 4597403, "mimeType": "video/mp4" } ], "flagged": false, "summary": "Android: Changing TabbedBar properties \"labels\" and \"index\" before opening window causes a crash", "creator": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "subtasks": [], "reporter": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "environment": null, "closedSprints": [ { "id": 1123, "state": "closed", "name": "2019 Sprint 7", "startDate": "2019-03-18T17:27:25.993Z", "endDate": "2019-03-30T17:27:00.000Z", "completeDate": "2019-03-29T18:02:37.441Z", "originBoardId": 114 }, { "id": 1108, "state": "closed", "name": "2019 Sprint 2", "startDate": "2019-01-14T17:20:19.067Z", "endDate": "2019-01-26T17:20:00.000Z", "completeDate": "2019-01-28T17:38:11.580Z", "originBoardId": 114 }, { "id": 1124, "state": "closed", "name": "2019 Sprint 8", "startDate": "2019-03-31T18:03:00.000Z", "endDate": "2019-04-12T18:03:00.000Z", "completeDate": "2019-04-12T19:04:50.175Z", "originBoardId": 114 }, { "id": 1109, "state": "closed", "name": "2019 Sprint 3", "startDate": "2019-01-28T17:38:43.075Z", "endDate": "2019-02-09T17:38:00.000Z", "completeDate": "2019-02-08T21:37:29.498Z", "originBoardId": 114 }, { "id": 1112, "state": "closed", "name": "2019 Sprint 4", "startDate": "2019-02-11T16:16:38.316Z", "endDate": "2019-02-23T16:16:00.000Z", "completeDate": "2019-02-24T18:35:43.422Z", "originBoardId": 114 }, { "id": 1118, "state": "closed", "name": "2019 Sprint 5", "startDate": "2019-02-24T18:36:06.435Z", "endDate": "2019-03-08T18:36:00.000Z", "completeDate": "2019-03-07T22:19:47.057Z", "originBoardId": 114 }, { "id": 1119, "state": "closed", "name": "2019 Sprint 6", "startDate": "2019-03-03T22:20:00.193Z", "endDate": "2019-03-15T22:20:00.000Z", "completeDate": "2019-03-18T17:26:43.120Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "445542", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "I can reproduce this issue with the below code.\r\n{code:javascript}\r\nvar window = Ti.UI.createWindow();\r\nvar tabbedBar = Ti.UI.createTabbedBar();\r\ntabbedBar.labels = [\"One\", \"Two\", \"Three\"];\r\nwindow.add(tabbedBar);\r\nwindow.open();\r\n{code}\r\n\r\nThanks for bringing this issue to our attention. We'll look into it.\r\n", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-01-23T03:57:43.000+0000", "updated": "2019-01-23T03:57:43.000+0000" }, { "id": "445610", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "PR (master): https://github.com/appcelerator/titanium_mobile/pull/10646", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-01-24T05:11:35.000+0000", "updated": "2019-01-24T05:11:35.000+0000" }, { "id": "445701", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Is there a chance to get this customer-prio bumped into 8.0.0? We need this for our production app and want to prevent curating a custom SDK.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2019-01-28T18:34:47.000+0000", "updated": "2019-01-28T18:34:47.000+0000" }, { "id": "445730", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "PR (8.0.x): https://github.com/appcelerator/titanium_mobile/pull/10655", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-01-29T01:21:58.000+0000", "updated": "2019-01-29T01:21:58.000+0000" }, { "id": "445731", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~hknoechel], out of curiosity, is there a reason why you can't set the labels/index via the {{TabbedBar}} creation properties? That would work-around the problem.", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-01-29T01:31:50.000+0000", "updated": "2019-01-29T01:31:50.000+0000" }, { "id": "445736", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "We have quite complex use cases where the index is adjusted based on user defaults (e.g. private vs shared expenses). Other use cases require the tabbed bar to change on runtime, e.g to change it's selection based on a certain state change. The only workaround for that would be to remove and re-add the whole tabbedbar, resulting in a flickering.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2019-01-29T07:37:43.000+0000", "updated": "2019-01-29T07:37:43.000+0000" }, { "id": "445830", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "[~jquick] Can you please present a working workaround for this? The priority is only \"medium\" and severity \"minor\", which is not correct. This makes tabbed-bars in real apps useless, since no change of state (= index) can be applied after creation. This blocks our current Android beta version in which we already need to jump from one workaround to another, which is really frustrating already.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2019-02-04T20:52:14.000+0000", "updated": "2019-02-04T20:52:14.000+0000" }, { "id": "445844", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "I think dynamically setting the {{TabbedBar}} \"labels\" and \"index\" properties via the window's \"open\" event is the best work-around for the moment.\r\n{code:javascript}\r\nvar window = Ti.UI.createWindow();\r\nvar tabbedBar = Ti.UI.createTabbedBar({\r\n\twidth: \"80%\",\r\n});\r\nwindow.add(tabbedBar);\r\nwindow.addEventListener(\"open\", function() {\r\n\ttabbedBar.labels = [\"One\", \"Two\", \"Three\"];\r\n\ttabbedBar.index = 2;\r\n});\r\nwindow.open();\r\n{code}\r\n\r\nAlternatively, you can add methods to the {{TabbedBar}} prototype like the below and update the properties via the initial \"postlayout\" event.\r\n{code:javascript}\r\n// Add this to your \"app.js\" or \"alloy.js\" file.\r\nTi.UI.TabbedBar.prototype.setLabelsWorkAround = function(labels) {\r\n\tthis.addEventListener(\"postlayout\", function onLayout(e) {\r\n\t\te.source.removeEventListener(e.type, onLayout);\r\n\t\te.source.labels = labels;\r\n\t});\r\n};\r\nTi.UI.TabbedBar.prototype.setIndexWorkAround = function(index) {\r\n\tthis.addEventListener(\"postlayout\", function onLayout(e) {\r\n\t\te.source.removeEventListener(e.type, onLayout);\r\n\t\te.source.index = index;\r\n\t});\r\n};\r\n\r\n// Use the above methods when setting labels/index before window has opened.\r\nvar window = Ti.UI.createWindow();\r\nvar tabbedBar = Ti.UI.createTabbedBar({\r\n\twidth: \"80%\",\r\n});\r\ntabbedBar.setLabelsWorkAround([\"One\", \"Two\", \"Three\"]);\r\ntabbedBar.setIndexWorkAround(2);\r\nwindow.add(tabbedBar);\r\nwindow.open();\r\n{code}\r\n\r\nWhat do you think?\r\n\r\n*_Edit:_*\r\n_I tried to override the prototype's \"index\" and \"labels\" properties via {{Object.defineProperty()}}, but these properties appear to be non-configurable when defined on the C++ side. I can't override them._", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-02-05T02:26:55.000+0000", "updated": "2019-02-05T03:17:25.000+0000" }, { "id": "445846", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Unfortunately that is no suitable workaround for us. We need to change the properties after the user does certain actions, so the open event is too early.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2019-02-05T06:49:22.000+0000", "updated": "2019-02-05T06:49:22.000+0000" }, { "id": "446911", "author": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "body": "FR Passed: Waiting on Jenkins builds. ", "updateAuthor": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-03-15T13:38:58.000+0000", "updated": "2019-03-15T13:38:58.000+0000" }, { "id": "447012", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "As described on GitHub, this causes bad glitches in our app once the activity containing this feature is reopened. A video is attached (private scope). After checking this further, it seems to cause an infinite loop (likely because different to iOS), setting the index causes a change event which triggers it again.\r\n\r\n*EDIT*: I could isolate it to the \"click\" event being fired too many times. I still need to compare the concrete behavior with iOS, but it definitely should not fire if:\r\n- the tabbed-bar was just created\r\n- the tabs change\r\n- a click against a tab that is already selected is done ", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2019-03-20T10:44:36.000+0000", "updated": "2019-03-20T11:31:21.000+0000" }, { "id": "447039", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~hknoechel], I'm not sure how to reproduce your issue. I tested it with the below and it did *NOT* get stuck in an infinite loop.\r\n{code:javascript}\r\nvar window = Ti.UI.createWindow({\r\n\tlayout: \"vertical\",\r\n});\r\nvar label = Ti.UI.createLabel({\r\n\ttop: \"30%\",\r\n});\r\nwindow.add(label);\r\nvar tabbedBar = Ti.UI.createTabbedBar({\r\n\tlabels: [\"One\", \"Two\", \"Three\"],\r\n\ttop: \"20dp\",\r\n\twidth: \"80%\",\r\n});\r\ntabbedBar.addEventListener(\"click\", function(e) {\r\n\tvar message = \"Selected Tab Index: \" + e.index;\r\n\tTi.API.info(\"@@@ \" + message);\r\n\tlabel.text = message;\r\n\r\n\t// Setting the TabbedBar.index to same index does not cause infinite loop.\r\n\ttabbedBar.index = e.index;\r\n});\r\nwindow.add(tabbedBar);\r\nwindow.addEventListener(\"focus\", function() {\r\n\t// Select tab \"Two\" when window opens and upon app resume.\r\n\ttabbedBar.index = 1;\r\n});\r\nwindow.open();\r\n{code}", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-03-21T01:38:27.000+0000", "updated": "2019-03-21T01:38:27.000+0000" }, { "id": "447443", "author": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "body": "*Closing ticket* Fix verified in SDK Version {{8.0.1.v20190402094527}} and SDK Version {{8.1.0.v20190402113644}}\r\n\r\nTest and other information can be found at:\r\nPR (master): https://github.com/appcelerator/titanium_mobile/pull/10646\r\nPR (8.0.x): https://github.com/appcelerator/titanium_mobile/pull/10655\r\n\r\n[~hknoechel] Feel free to reopen the ticket if you are still experiencing issues with steps on how to reproduce the issue. ", "updateAuthor": { "name": "smohammed", "key": "smohammed", "displayName": "Samir Mohammed", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2019-04-03T09:26:24.000+0000", "updated": "2019-04-03T09:26:24.000+0000" } ], "maxResults": 13, "total": 13, "startAt": 0 } } }