{ "id": "160571", "key": "TIMOB-23447", "fields": { "issuetype": { "id": "4", "description": "An improvement or enhancement to an existing feature or task.", "name": "Improvement", "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": [], "resolution": null, "resolutiondate": null, "created": "2016-05-27T12:04:55.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "android", "community", "remove", "speed" ], "versions": [], "issuelinks": [], "assignee": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "updated": "2017-08-11T14:52:37.000+0000", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "The current implementation of [removeAllChildren()|https://github.com/appcelerator/titanium_mobile/blob/415bd6c66dcc55b1a59a59574f3babd3c3a84ede/android/titanium/src/java/org/appcelerator/titanium/proxy/TiViewProxy.java#L719] creates a copy of all views and removes each view in a while loop.\r\nThe people at Shockoe showed in a [blog post|http://shockoe.com/development/profiling-titanium/] that it takes up to 24 seconds to remove 1000 views with \r\n{code:java}\r\ntheWindow.removeAllChildren();\r\n{code}\r\n\r\nChanging the TiViewProxy method to use the native [ViewGroup.removeAllViews()|https://developer.android.com/reference/android/view/ViewGroup.html#removeAllViews%28%29] would bring down delay below 100ms!\r\n\r\n*Test app:*\r\nhttps://github.com/bpulley/titanium-profiling can be used to test the behavior. Just run the \"Remove views en masse\" test.\r\n\r\n\r\n\r\n{code:java}\r\nvar win = Ti.UI.createWindow({\r\n backgroundColor: \"white\"\r\n});\r\n\r\nvar view = Ti.UI.createView({\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n height: 100,\r\n layout: \"horizontal\"\r\n});\r\n\r\nvar scrollview = Ti.UI.createScrollView({\r\n top: 100,\r\n left: 0,\r\n right: 0,\r\n height: 100,\r\n layout: \"horizontal\",\r\n type: \"horizontal\"\r\n});\r\n\r\nfor (var i = 0; i < 100; i++) {\r\n var v = Ti.UI.createView({\r\n width: 10,\r\n height: 10,\r\n backgroundColor: \"red\",\r\n left: 10\r\n });\r\n view.add(v);\r\n v = null;\r\n\r\n var v2 = Ti.UI.createView({\r\n width: 10,\r\n height: 10,\r\n backgroundColor: \"red\",\r\n left: 10\r\n });\r\n scrollview.add(v2);\r\n v2 = null;\r\n}\r\n\r\n// Listview\r\n\r\nvar listView = Ti.UI.createListView({\r\n top: 200,\r\n height: 100\r\n});\r\nvar sections = [];\r\n\r\nvar fruitSection = Ti.UI.createListSection({\r\n headerTitle: 'Fruits'\r\n});\r\nvar fruitDataSet = [{\r\n properties: {\r\n title: 'Apple'\r\n }\r\n}, {\r\n properties: {\r\n title: 'Banana'\r\n }\r\n}, ];\r\nfruitSection.setItems(fruitDataSet);\r\nsections.push(fruitSection);\r\n\r\nvar vegSection = Ti.UI.createListSection({\r\n headerTitle: 'Vegetables'\r\n});\r\nvar vegDataSet = [{\r\n properties: {\r\n title: 'Carrots'\r\n }\r\n}, {\r\n properties: {\r\n title: 'Potatoes'\r\n }\r\n}, ];\r\nvegSection.setItems(vegDataSet);\r\nsections.push(vegSection);\r\n\r\nlistView.sections = sections;\r\n\r\nvar fishSection = Ti.UI.createListSection({\r\n headerTitle: 'Fish'\r\n});\r\nvar fishDataSet = [{\r\n properties: {\r\n title: 'Cod'\r\n }\r\n}, {\r\n properties: {\r\n title: 'Haddock'\r\n }\r\n}, ];\r\nfishSection.setItems(fishDataSet);\r\n\r\nfunction onOpen(e) {\r\n var startTime = new Date();\r\n console.log(\"View length: \" + view.getChildren().length);\r\n view.removeAllChildren();\r\n console.log(\"View after remove length: \" + view.getChildren().length);\r\n\r\n console.log(\"ScrollView length: \" + scrollview.getChildren().length);\r\n scrollview.removeAllChildren();\r\n console.log(\"ScrollView after remove length: \" + scrollview.getChildren().length);\r\n\r\n console.log(\"ListView length: \" + listView.getSections().length);\r\n listView.removeAllChildren();\r\n console.log(\"ListView after remove length: \" + listView.getSections().length);\r\n \r\n var endTime = new Date();\r\n\tvar delta = endTime - startTime;\r\n alert('time ' + delta + 'ms');\r\n}\r\n\r\nwin.add(listView);\r\nwin.add(view);\r\nwin.add(scrollview);\r\nwin.addEventListener(\"open\", onOpen);\r\nwin.open();\r\n{code}\r\n\r\nTi SDK 5.2.2 = 4160ms (and listview.removeAllViews() is not working)\r\nPatched Version = 333ms (listview will be empty)", "attachment": [], "flagged": false, "summary": "Android: Optimize removeAllChildren()", "creator": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "subtasks": [], "reporter": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "environment": null, "comment": { "comments": [ { "id": "387027", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "I'm still testing the PR in various situations. It is working already with normal `Views` and `ScrollViews`. Both showed a big time improvement.", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-05-27T12:11:13.000+0000", "updated": "2016-05-27T12:11:13.000+0000" }, { "id": "387031", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "Added example and listview is working, too", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-05-27T14:51:08.000+0000", "updated": "2016-05-27T14:51:08.000+0000" }, { "id": "387032", "author": { "name": "sdarda", "key": "sdarda", "displayName": "Sharif AbuDarda", "active": false, "timeZone": "Asia/Dhaka" }, "body": "Hello,\r\n\r\nI tried to test the issue. Here are my findings. \r\n\r\nClassic code provided above:\r\n1. Android Emulator (6.0.0)- 4482ms(1st run), 3716ms(2nd run).\r\n2. Android Device (4.4.2)- 4658ms.\r\n\r\nAlloy sample in Github\r\n1. Android Emulator (6.0.0)- Removed 1000 views in 18860ms.\r\n2. Android Device (4.4.2)- Removed 1000 views in 13954ms.\r\n\r\nListview removeAllChildren() needs to be optimized. \r\n\r\nRegards,\r\nSharif.", "updateAuthor": { "name": "sdarda", "key": "sdarda", "displayName": "Sharif AbuDarda", "active": false, "timeZone": "Asia/Dhaka" }, "created": "2016-05-27T15:22:52.000+0000", "updated": "2016-05-27T15:22:52.000+0000" }, { "id": "387036", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "Those numbers are with the PR or without?", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-05-27T16:43:42.000+0000", "updated": "2016-05-27T16:43:42.000+0000" }, { "id": "387572", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "Removed the ListView part! The `removeAllChildren()` inside the TiListView doesn't remove the ListViewItems in the current SDKs (as they are not chlidren of the ListView), so I don't need to do it in this PR. I just added an if-part so it won't produce an error if you call it on a ListView (behaves the same as in e.g. 5.2.2.GA).", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-06-04T21:17:29.000+0000", "updated": "2016-06-04T21:17:29.000+0000" }, { "id": "388324", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "@sdarda did you test it with the patch, too?\r\n\r\nAny other notes on the behavior? It will just work on View with children, so ListView is not included (and works like before)", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-06-14T18:23:54.000+0000", "updated": "2016-06-14T18:23:54.000+0000" }, { "id": "389156", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "Using the app from the blogpost and android monitor heap:\r\n\r\n*before:*\r\n!http://migaweb.de/mem1.png!\r\n\r\n\r\n*during creation*\r\n!http://migaweb.de/mem2.png!\r\n!http://migaweb.de/mem3.png!\r\n\r\n\r\n*after deleting the views and pressing GC:*\r\n!http://migaweb.de/mem4.png!", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-06-27T19:20:35.000+0000", "updated": "2016-06-27T19:20:35.000+0000" }, { "id": "389203", "author": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "body": "The PR by [~michael] for this ticket is here: https://github.com/appcelerator/titanium_mobile/pull/8026", "updateAuthor": { "name": "msamah", "key": "msamah", "displayName": "Ashraf Abu", "active": false, "timeZone": "Asia/Singapore" }, "created": "2016-06-28T01:36:44.000+0000", "updated": "2016-06-28T01:36:44.000+0000" }, { "id": "403416", "author": { "name": "hazemkhaled", "key": "hazemkhaled", "displayName": "Hazem Khaled", "active": true, "timeZone": "Europe/Istanbul" }, "body": "It'll be great if you release this issue with TIMOB-19482 together 6.1.0 :)", "updateAuthor": { "name": "hazemkhaled", "key": "hazemkhaled", "displayName": "Hazem Khaled", "active": true, "timeZone": "Europe/Istanbul" }, "created": "2016-12-15T10:38:06.000+0000", "updated": "2016-12-15T10:38:06.000+0000" } ], "maxResults": 9, "total": 9, "startAt": 0 } } }