Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-20038] Android: TableView crashes when scrolling more than 29 rows

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2016-02-02T08:33:21.000+0000
Affected Version/stitanium 5.0.5
Fix Version/sRelease 5.2.0
ComponentsAndroid
Labelsandroid
ReporterAdam Fennell
AssigneeHieu Pham
Created2015-10-07T14:33:08.000+0000
Updated2016-04-11T13:19:19.000+0000

Description

When executing the following code, if there are more than 29 rows, the app will crash when scrolling back up from the bottom of the TableView: (You may need to try more than 30 rows for the app to crash, as each device may vary this number)
var section = Ti.UI.createTableViewSection();
var numberOfRows = 30;	//if > 29 the app will crash when scrolling back up from the bottom

for (var i=0; i < numberOfRows; i++)	 
{	
	//fill section with rows	
	section.add(Ti.UI.createTableViewRow({
		height: 50,
		width: Ti.UI.FILL,
		backgroundColor: 'green',
		className: 'row' + i
	}));
};

var table = Ti.UI.createTableView({
	top: 0,
	left: 0,
	height: Ti.UI.FILL,
	width: Ti.UI.FILL,
	data: [ section ]
});

var window = Ti.UI.createWindow({
	fullscreen: true		
});

window.add(table);
window.open();
*The error log from the Studio console is:*
[ERROR] :  InputEventReceiver: Exception dispatching input event.
[DEBUG] :  AndroidRuntime: Shutting down VM
[WARN] :   dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x410532a0)
[ERROR] :  TiApplication: (main) [25408,25408] Sending event: exception on thread: main msg:java.lang.ArrayIndexOutOfBoundsException: length=32; index=32; Titanium 3.5.1,2015/03/05 10:08,96875c9
[ERROR] :  TiApplication: java.lang.ArrayIndexOutOfBoundsException: length=32; index=32
[ERROR] :  TiApplication: 	at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:7127)
[ERROR] :  TiApplication: 	at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5694)
[ERROR] :  TiApplication: 	at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3424)
[ERROR] :  TiApplication: 	at android.widget.AbsListView.onTouchEvent(AbsListView.java:4099)
[ERROR] :  TiApplication: 	at android.view.View.dispatchTouchEvent(View.java:7350)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2464)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2197)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
[ERROR] :  TiApplication: 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
[ERROR] :  TiApplication: 	at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2151)
[ERROR] :  TiApplication: 	at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1480)
[ERROR] :  TiApplication: 	at android.app.Activity.dispatchTouchEvent(Activity.java:2469)
[ERROR] :  TiApplication: 	at android.support.v7.app.ActionBarActivityDelegateICS$WindowCallbackWrapper.dispatchTouchEvent(ActionBarActivityDelegateICS.java:268)
[ERROR] :  TiApplication: 	at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2099)
[ERROR] :  TiApplication: 	at android.view.View.dispatchPointerEvent(View.java:7535)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3492)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3424)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4534)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4512)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4616)
[ERROR] :  TiApplication: 	at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
[ERROR] :  TiApplication: 	at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
[ERROR] :  TiApplication: 	at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4584)
[ERROR] :  TiApplication: 	at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4635)
[ERROR] :  TiApplication: 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
[ERROR] :  TiApplication: 	at android.view.Choreographer.doCallbacks(Choreographer.java:555)
[ERROR] :  TiApplication:
[ERROR] :  TiApplication: 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
[ERROR] :  TiApplication: 	at android.os.Handler.handleCallback(Handler.java:615)
[ERROR] :  TiApplication: 	at android.os.Handler.dispatchMessage(Handler.java:92)
[ERROR] :  TiApplication: 	at android.os.Looper.loop(Looper.java:137)
[ERROR] :  TiApplication: 	at android.app.ActivityThread.main(ActivityThread.java:4921)
[ERROR] :  TiApplication: 	at java.lang.reflect.Method.invokeNative(Native Method)
[ERROR] :  TiApplication: 	at java.lang.reflect.Method.invoke(Method.java:511)
[ERROR] :  TiApplication: 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
[ERROR] :  TiApplication: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
[ERROR] :  TiApplication: 	at dalvik.system.NativeStart.main(Native Method)
I have tried removing the "className" property from the TableViewRow, which stops the crashing, but prevents Buttons and other Views inside the TableViewRow redrawing correctly, so must be left in (as indicated by the Appcelerator Platform Docs). Due to our customers using JellyBean devices, we need the fix in 3.5.1 or 3.5.2, as the devices can't be upgraded to newer Android versions. *Possible Cause:* This may be caused by an issue with 0-Based indexes used in getItemViewType() or getViewTypeCount() in titanium_mobile/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/TiListView.java

Comments

  1. Adam Fennell 2015-10-15

    Could you let me know if this is something you are looking into? It would be great if I could update our customers, as this is a work stop issue for them.
  2. Hieu Pham 2015-12-08

    The problem here is this:
       className: 'row' + i
       
    "className" is used for internal recycling purposes (i.e: speeds up loading time for table view). Currently we support up to 32 different classNames (or row layouts). In your example, there is only one row layout, so you only need one className. Please look at http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.TableViewRow-property-className for more info. I will expose a property to change the default '32', but for this case you should only use one className.
  3. Adam Fennell 2015-12-08

    Thanks for looking into this. The example code I posted was to highlight the issue. In our actual app, we have (or would like to have) 40 rows with different layouts i.e. no rows have the same layout of views. Am I right to say then: 1. We would use: *className: 'row' + i* ? 2. We would set the newly exposed property from 32 to 40? Also, would there be a negative effect on performance or memory consumption if this exposed property is, for example, set to 100?
  4. Hieu Pham 2015-12-08

    master PR: https://github.com/appcelerator/titanium_mobile/pull/7558 testing code:
       var section = Ti.UI.createTableViewSection();
       var numberOfRows = 35;	//if > 29 the app will crash when scrolling back up from the bottom
        
       for (var i=0; i < numberOfRows; i++)	 
       {	
       	//fill section with rows	
       	section.add(Ti.UI.createTableViewRow({
       		height: 50,
       		width: Ti.UI.FILL,
       		backgroundColor: 'green',
       		className: 'row' + i
       	}));
       };
        
       var table = Ti.UI.createTableView({
       	top: 0,
       	left: 0,
       	maxClassname: 100,
       	height: Ti.UI.FILL,
       	width: Ti.UI.FILL,
       	data: [ section ]
       });
        
       var window = Ti.UI.createWindow({
       	fullscreen: true		
       });
        
       window.add(table);
       window.open();
       
  5. Ashraf Abu 2015-12-09

    PR merged. Adding https://github.com/appcelerator/titanium_mobile/pull/7561 to update doc from 6.0.0 to 5.2.0.
  6. Ashraf Abu 2015-12-09

    Doc PR merged.
  7. Josh Longton 2016-01-15

    Following are my observations I found while checking the fix: If "maxClassName" is set to two more or less than the number of rows then the app crashes while scrolling up from the bottom. If "maxClassName" is set to three or more than the number of rows then the app does not crash while scrolling up from the bottom. Reopening Tested on: 
iPhone 6s Plus Device (9.1) 
Mac OSX El Capitan 10.11.2 (15C50) 
Studio: 4.4.0.201511241829 Ti SDK: 5.2.0.v20160114021251 
Appc NPM: 4.2.2
 App CLI: 5.2.0-224 Xcode 7.2
 Node v4.2.4
  8. Hieu Pham 2016-02-01

    Josh, that is because we have some default class names mapping as well. Like I said, the use case for "maxClassname" is not practical in the scenario described above. You should only use 1 className per row UI, not row, for performance purposes.
  9. Josh Longton 2016-02-05

    The application is crashing still even without scrolling

    Load the application

    Rotate or open multitasking

    the app crashes

       var section = Ti.UI.createTableViewSection();
       var numberOfRows = 2;   
       for (var i=0; i < numberOfRows; i++)     
       {    
           //fill section with rows    
           section.add(Ti.UI.createTableViewRow({
               height: 50,
               width: Ti.UI.FILL,
               backgroundColor: 'white',
               color:'black',
               className: 'row' + i,
               title: 'row' + i
           }));
       };
        
       var table = Ti.UI.createTableView({
           top: 0,
           left: 0,
           maxClassname: 3,
           height: Ti.UI.FILL,
           width: Ti.UI.FILL,
           data: [ section ]
       });
        
       var window = Ti.UI.createWindow({
           fullscreen: true        
       });
        
       window.add(table);
       window.open();
       
       
  10. Chee Kiat Ng 2016-02-05

    2 things. If the use case is not practical for "maxClassname" can we: 1. Describe in documentation of the proper use of maxClassname 2. fail elegantly instead of crashing if maxClassname is misused.
  11. Lokesh Choudhary 2016-02-08

    Verified the fix. There is no crash when maxClassName is is set to two more or less than the number of rows. Closing. Environment: Appc Studio : 4.5.0.201602070910 Ti SDK : 5.2.0.v20160208101502 Ti CLI : 5.0.6 Alloy : 1.7.33 MAC Yosemite : 10.10.5 Appc NPM : 4.2.3-2 Appc CLI : 5.2.0-249 Node: 4.2.2 Nexus 5 - Android 5.1.1

JSON Source