[TIMOB-25728] Android: TableView can crash using setData()
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Critical |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2018-02-21T19:26:28.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Release 7.1.0 |
Components | Android |
Labels | SDK, android, tableView |
Reporter | Nigel Underwood |
Assignee | Gary Mathews |
Created | 2017-08-30T07:51:59.000+0000 |
Updated | 2018-03-14T18:13:12.000+0000 |
Description
I have a tableview in a View XML and it crashes when I set the data via setData on SK6. Works fine on SDK 5, but on SDK6 it crashes on Android when I assign the same data twice which I do when I need to switch data sets. This is only on Android as iOS works as it should
$.table.setData(myDataSet);
$.table.data = [];
$.table.setData(newDataSet); // This is ok
$.table.data = [];
$.table.setData(anotherNewDataSet); // This is ok
$.table.data = [];
$.table.setData(myDataSet); // Re-assigning myDataSet crashes the app
I am guessing this is a bug in SDK6 for Android. I've done some further testing and it only crashes if the SAME dataset is assigned twice, I can keep adding new datasets and it won't crash, but assign the same dataset again and it crashes.
Thanks
Nigel
[~developer@tpglobalpartners.com] I cannot reproduce your issue. Do you have a test case that reproduces this issue?
Thanks for the update. The data I Aden is based on a complex view containing sub views. I shall be back at work on Monday and will upload an example app that fails.
Hello, We have tested this issue with 6.1.2.GA and 6.2.0.GA using the sample code above. We have been unable to reproduce this . [~developer@tpglobalpartners.com] can you please share the test code here to reproduce this on our end?
I have been trying to create test code that reproduces the issue which is proving a little difficult. I have however rooted out a cause of the issue so will try and build a test case around this. The cause is around how Android is managing Controller Views in an array thats assigned to a tableview. If in the above example, data_a and data_b are array's of controller views (derived from controller.getView() ), then assigning these again to the tableview causes the issue. However if I recreated the array of controller views each time before reassigning to the tableview, then this seems in the main to resolve the issue, though it still crashes but not so often. As detailed, this is fine on SDK5 on Android and iOS, the issue exists only on SDK 6 with Android so I am doubting its an issue with my coding but more with the memory management within the SDK 6.
Hello, we need a valid sample code that regenerates the issue, so we can move this ticket for a fix.
I know I need to get this done - finishing the app off using SDK 5 to meet the project deadlines. I will look to upload some sample code in a weeks time.
Hello [~developer@tpglobalpartners.com], did you get around making the sample code? please share with us. Thanks.
I started to make a test app then got diverted onto another SDK 6 issue where by click events defined in an XML view file result in the error message = "Can't find variable: <
[~developer@tpglobalpartners.com], We are not clear about the the error "message = "Can't find variable: <
Hello [~developer@tpglobalpartners.com], I just wanted to follow up here. Did you manage to follow the recommended steps provided earlier? Let us know if you still experience any issue. We would be happy to assist you. Best Regards!
Still have issues and I am finding the final release of SDK5 far more bug free than SDK6. Will try and wrap up all the issues in a single app if possible. Got some tight deadlines for this week and then I can work on replicating the issues in a self contained app
[~developer@tpglobalpartners.com], Thanks for your feedback. Please test on the latest SDK 6.3.0.GA and let us know how it goes. We will be waiting for your sample test code to reproduce the issue on our end. Best
Hello, Try to test on latest SDK 7.0.0.GA. And let us know.
So tried this on the latest SDK 7 and its actually worse, so probably means its easier to replicate. Seems that from SDK 6, complex table rows made up of multiple controllers seems to break the tableview - as I said, works fine in SDK5.
[~developer@tpglobalpartners.com] Are you able to provide a test case that we can use to debug and fix the issue?
I will try and produce a test case for this and also another one where text is no longer justified in SDK6 and 7.
[~developer@tpglobalpartners.com], Did you manage to produce a test case so that we can test on our end?
I am encountering the same issue with 7.0.1.GA on an Android 5.0.1 device. I will try to produce a test case, but have uploaded the console error output: [https://pastebin.com/GF4kRmKG](https://pastebin.com/GF4kRmKG) In my application, I have custom table view rows created the "classic" way (Ti.UI.createTableViewRow), each with a custom view added. Each row is pushed to a table row array, and then the table data is set with setData(). The issue arises where the table row array is recreated with new rows, and setData() is called; it is rather finicky as sometimes either no crash occurs, the crash occurs directly upon setting the data, or the table view updates successfully but has to be scrolled down slightly until the border of the bottom row, at which time the crash immediately occurs (presumably as soon as the next row is loaded/rendered).
This sounds basically the same issue I am having - using an Array and setData. The array contains a custom tableview which is made up of several views.
Yep, exactly that. I've been unable to construct a test case, however am able to reliably produce the bug in an application I'm working on at the moment. I'll provide updates if I can produce a working test case.
I've just not been able to reproduce a test case - like you, it fails in the app we have. I think this is all linked to memory management as it's fine in SDK5, but fails in SDK6 and its worse in SDK7.
That certainly makes sense, lots of background SQLite/remote stuff happening in the background here when the issue happens. In my case things work perfectly fine up up to 6.3.0GA; SDK7 is where the trouble starts.
I have had the same issue, it seems to be an issue with Android and the UI thread. I have been experiencing a lot of UI thread main exceptions errors in the recent SDKs (TableView FooterView also causes crashes in 7.01 GA on Android). My use case was filtering TableView data. The workaround for me was to create a HTTP call to use as a worker thread, then call the function to setData. This separated the setData from the main UI thread, and voila no more crashes (for now). I have seen post regarding a Ti.Worker module, that also may work in some use cases.
Sounds like a good shout Michael on your workaround - not ideal but if it fixes the issue then its good for me. Will give this a go later and post back if this works for me also.
This sounds promising Michael, I'll give it a shot - if it works then that's definitely better than downgrading the SDK. Will keep the thread posted. Kudos!
I've been unable to get the workaround working that Michael suggested, at this point I'm rolling back to 6.3.0GA for Android. When I get a chance I'll try again to produce a test case, but I am able to reproduce the bug every time within a production-ready application.
Hello [~findawebguy], Can you provide the sample code on your suggested workaround? Thanks.
Sure. As stated above it only occurs with TableViewRows that contain views, not sure if the complexity of the view is the issue or is the issue the the view was not yet rendered (didn't scroll down far enough yet). In the situation I am having, the app crashes as soon as I attempt to scroll the TableView after the second setData filtering the views (calling applyFilters directly). It errors out with "Sending event: exception on thread: main msg:java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View org.appcelerator.titanium.view.TiUIView.getOuterView()' on a null object reference; Titanium 7.0.1" The HTTP worker created seemed to resolve the issue. Here is some quick pseudocode I put together with the HTTP worker. +index.js+ var data = []; var utils = require("utils"); function setFilter(){ //additional application logic is done here based on the arguments sent in //applyFilters(); utils.worker(applyFilters,[]); }; function applyFilters() { data = []; $.MyTableView.setData(data); //views created and added to data based on filtered results { .. .. data.push(view) } $.MyTableView.setData(data); } +utils.js+ exports.worker = function(func,params){ var client = Ti.Network.createHTTPClient({ onload: function(e) { func.apply(null,params); }, onerror: function(e) { func.apply(null,params); }, timeout:500 }); var url = "/worker.html"; client.open("GET", url); client.send(); };
Hello [~developer@tpglobalpartners.com], [~jrautenbach], Can you follow up on the [~findawebguy], comment on the workaround suggested above? Try this workaround as provided details above. Thanks.
OK so I have tried the worker approach and this has resolve the immediate crashing in that I can populate the tableview. However as per the original issue, if I go to populate the tableview with a second set of data and then re-assign the 1st data set, then the app crashes again. Crashes out with the following console warning [WARN] : dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xa4b7c648)
I am curious if the problem is setData or setRowData? This could possibly be two different issues. Below is a common error I have in the crash logs under the Google Play Console: java.lang.NullPointerException: at ti.modules.titanium.ui.widget.tableview.TiTableViewRowProxyItem.createControls (TiTableViewRowProxyItem.java:244) at ti.modules.titanium.ui.widget.tableview.TiTableViewRowProxyItem.setRowData (TiTableViewRowProxyItem.java:423) at ti.modules.titanium.ui.widget.tableview.TiTableViewRowProxyItem.setRowData (TiTableViewRowProxyItem.java:86) at ti.modules.titanium.ui.widget.tableview.TiTableView$TTVListAdapter.getView (TiTableView.java:254) at android.widget.AbsListView.obtainView (AbsListView.java:3251) at android.widget.ListView.makeAndAddView (ListView.java:2147) at android.widget.ListView.fillUp (ListView.java:803) at android.widget.ListView.fillGap (ListView.java:740) at android.widget.AbsListView.trackMotionScroll (AbsListView.java:8319) at android.widget.ListView.trackMotionScroll (ListView.java:2065) at android.widget.AbsListView.scrollIfNeeded (AbsListView.java:4923) ....
Hello, [~developer@tpglobalpartners.com], Can you get back on [~findawebguy], comment above?
I attempted Michael's workaround but unfortunately it hasn't solved the problem. The crash is per usual, with the same crash log as I posted earlier. Apologies for the late reply.
After running logcat and viewing the output - issue is certainly with setRowData. E/AndroidRuntime( 2711): FATAL EXCEPTION: main E/AndroidRuntime( 2711): java.lang.NullPointerException E/AndroidRuntime( 2711): at ti.modules.titanium.ui.widget.tableview.TiTableViewRowProxyItem.setRowData(TiTableViewRowProxyItem.java:348) E/AndroidRuntime( 2711): at ti.modules.titanium.ui.TableViewRowProxy.setProperty(TableViewRowProxy.java:192) E/AndroidRuntime( 2711): at ti.modules.titanium.ui.TableViewProxy.rowProxyFor(TableViewProxy.java:714) E/AndroidRuntime( 2711): at ti.modules.titanium.ui.TableViewProxy.processData(TableViewProxy.java:629) E/AndroidRuntime( 2711): at ti.modules.titanium.ui.TableViewProxy.handleSetData(TableViewProxy.java:691) E/AndroidRuntime( 2711): at ti.modules.titanium.ui.TableViewProxy.handleMessage(TableViewProxy.java:872) E/AndroidRuntime( 2711): at android.os.Handler.dispatchMessage(Handler.java:95) E/AndroidRuntime( 2711): at android.os.Looper.loop(Looper.java:137) E/AndroidRuntime( 2711): at android.app.ActivityThread.main(ActivityThread.java:5103) E/AndroidRuntime( 2711): at java.lang.reflect.Method.invokeNative(Native Method) E/AndroidRuntime( 2711): at java.lang.reflect.Method.invoke(Method.java:525) E/AndroidRuntime( 2711): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) E/AndroidRuntime( 2711): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) E/AndroidRuntime( 2711): at dalvik.system.NativeStart.main(Native Method)
Hello [~developer@tpglobalpartners.com], Please share the full reproducible sample code/sample project that reproduces the issue for "setRowData". I will verify the issue and move to TIMOB for a fix. Thanks.
As with the others in this thread, it exists in our production ready applications and its difficult to produce a standalone example that fails
I have managed to create a workaround now by using a combination of a worker thread and recreating the table rows every time. This has fixed the issue and it seems that if a row array was reused in setData, then a null exception would occur. If I recreate the row array every time, then calling setData works fine - no NULL exception. I know my coding was fine in SDK5, as the issue came up in SDK6 and in SDK7, the app stopped working completely due to this issue. So for now, I have a workaround that seems to be robust.
master: https://github.com/appcelerator/titanium_mobile/pull/9774
[Here's an SDK build of the above PR](https://www.dropbox.com/s/2pmr9osq3iacxjv/mobilesdk-7.1.0.v20180126114513-osx.zip?dl=1) if anyone would like to give it a try. I believe there were two issues causing this crash, TIMOB-25656 and improper validation of the background selectors.
Hi Gary, I can confirm the PR's solved the issue on my end! Working perfectly. Many thanks!
Works for me also Gary - thanks for the fix, now I can continue on SDK 7. Many thanks.
FR passed. Waiting for merge to be enabled.
7_1_X: https://github.com/appcelerator/titanium_mobile/pull/9839
FR passed for both master & backport.
PR's merged.
I HAVE TRIED 7.1.0.RC IT USED TO WORK PROPERLY IN THE PAST ... tableData[2] = tableViewSection3; tableView.data = tableData; HOWEVER, NOW IT ONLY WORKS THIS: tableView.updateSection(2, tableViewSection3); function createTableViewRow(e) { var rowView = Titanium.UI.createTableViewRow({ height:'120dip' }); rowView.add(Titanium.UI.createLabel({ height:Ti.UI.SIZE, left:'10dip', right:'10dip', text:'Text', textAlign:Titanium.UI.TEXT_ALIGNMENT_LEFT, verticalAlign:Titanium.UI.TEXT_VERTICAL_ALIGNMENT_CENTER, font:{fontSize:'20sp', fontWeight:'normal', fontFamily:'Tahoma'}, color:'#000' })); return(rowView); } var win = Ti.UI.createWindow(); var tableData = []; var tableView = Titanium.UI.createTableView({ separatorStyle:Ti.UI.TABLE_VIEW_SEPARATOR_STYLE_NONE }); var tableViewSection1 = Ti.UI.createTableViewSection(); var tableViewSection2 = Ti.UI.createTableViewSection(); var tableViewSection3 = Ti.UI.createTableViewSection(); tableData.push(tableViewSection1); tableData.push(tableViewSection2); tableData.push(tableViewSection3); tableView.data = tableData; win.add(tableView); var setData = function(e) { tableViewSection3.add(createTableViewRow()); tableViewSection3.add(createTableViewRow()); tableViewSection3.add(createTableViewRow()); //tableView.updateSection(2, tableViewSection3); tableData[2] = tableViewSection3; tableView.data = tableData; }; win.addEventListener('open', function(e) { setData(); }); win.open();
Verified the fix in SDK 7.1.0.v20180308150545 & 7.2.0.v20180313125304. Closing. Studio Ver: 5.0.0.201712081732 OS Ver: 10.13.2 Xcode Ver: Xcode 9.2 Appc NPM: 4.2.12 Appc CLI: 7.0.2 Daemon Ver: 1.0.1 Ti CLI Ver: 5.0.14 Alloy Ver: 1.11.0 Node Ver: 8.9.1 NPM Ver: 5.5.1 Java Ver: 1.8.0_101 Devices: ⇨ google Nexus 5 — Android 6.0.1 ⇨ google Nexus 6P — Android 8.0.0