Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-26890] Android: Switch between TabGroup tabs 1 and 4 sometimes crashes the app as of 8.0.0

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2019-04-29T14:43:17.000+0000
Affected Version/sRelease 8.0.0
Fix Version/sRelease 8.0.1
ComponentsAndroid
LabelsTabGroup, android, engSchedule, regression
ReporterAndreas Pingas
AssigneeJoshua Quick
Created2019-03-05T12:23:44.000+0000
Updated2019-04-29T14:43:17.000+0000

Description

*Summary:* As of Titanium 8.0.0, a TabGroup with 4 or more tabs can sometimes crash when switching between tab 1 and 4. This depends on the content within the tab. This is a regression. *Steps to reproduce:*

Build and run the below code on Android.

Tap on "Tab 5".

Tap on "Tab 1".

Notice the app crashes/hangs.

function createDayView(e) {
	var dayView = Titanium.UI.createView({
		height: '80dip',
		width: '66dip',
		top: '0dip',
		backgroundColor: '#FFF'
	});
	var boxView = Titanium.UI.createView({
		height: '56dip',
		width: '56dip',
		top: '10dip',
		right: '10dip',
		touchEnabled: false
	});
	dayView.add(boxView);
	var date = new Date(e.date);
	var backgroundView = Ti.UI.createView({
		height: '56dip',
		width: '56dip',
		borderRadius: '14dip',
		backgroundColor: '#AAA',
		touchEnabled: false
	});
	boxView.add(backgroundView);
	var verticalView = Ti.UI.createView({
		height: Ti.UI.SIZE,
		width: Ti.UI.SIZE,
		layout: 'vertical'
	});
	boxView.add(verticalView);
	verticalView.add(Titanium.UI.createLabel({
		height: Ti.UI.SIZE,
		width: Ti.UI.SIZE,
		text: date.getDate(),
		ellipsize: Titanium.UI.TEXT_ELLIPSIZE_TRUNCATE_END,
		textAlign: Titanium.UI.TEXT_ALIGNMENT_CENTER,
		verticalAlign: Titanium.UI.TEXT_VERTICAL_ALIGNMENT_CENTER,
		font: { fontSize: '24sp', fontWeight: 'bold', fontFamily: 'Tahoma' },
		color: '#FFF',
		touchEnabled: false
	}));
	verticalView.add(Titanium.UI.createLabel({
		height: Ti.UI.SIZE,
		width: Ti.UI.SIZE,
		text: 'OK',
		horizontalWrap: false,
		ellipsize: Titanium.UI.TEXT_ELLIPSIZE_TRUNCATE_END,
		textAlign: Titanium.UI.TEXT_ALIGNMENT_CENTER,
		verticalAlign: Titanium.UI.TEXT_VERTICAL_ALIGNMENT_CENTER,
		font: { fontSize: '10sp', fontWeight: 'bold', fontFamily: 'Tahoma' },
		color: '#FFF',
		touchEnabled: false
	}));
	return (dayView);
}

function createMenuView(e) {
	var menuView = Titanium.UI.createView({
		height: '80dip',
		top: '0dip',
		backgroundColor: '#FFF'
	});
	var scrollView = Titanium.UI.createScrollView({
		scrollType: 'horizontal',
		layout: 'horizontal'
	});
	menuView.add(scrollView);
	var dayViewData = [];
	for (var i = 0; i < 12; i++) {
		var date = new Date();
		date.setDate(date.getDate() + i);
		var dayView = createDayView({
			date: date
		});
		dayViewData.push(dayView);
		scrollView.add(dayView);
	}
	return (menuView);
}

function createTabView(win) {
	var containerView = Titanium.UI.createView({
		top: '80dip',
		bottom: '0dip',
		backgroundColor: '#FFF'
	});
	win.add(containerView);
	var tableData = [];
	var menuView = createMenuView();
	win.add(menuView);
	var tableView = Titanium.UI.createTableView({
		backgroundColor: '#FFF',
		separatorStyle: Titanium.UI.TABLE_VIEW_SEPARATOR_STYLE_SINGLE_LINE,
		tableSeparatorInsets: { left: '0dip', right: '0dip' }
	});
	var section1 = Ti.UI.createTableViewSection();
	var section2 = Ti.UI.createTableViewSection();
	tableData.push(section1);
	tableData.push(section2);
	tableView.data = tableData;
	containerView.add(tableView);
	var iconView = Titanium.UI.createView({
		height: '60dip',
		width: '60dip',
		right: '25dip',
		bottom: '25dip',
		zIndex: 100000
	});
	iconView.add(Titanium.UI.createImageView({
		height: '60dip',
		width: '60dip',
		touchEnabled: false
	}));
	win.add(iconView);
};

var window1 = Ti.UI.createWindow();
var window2 = Ti.UI.createWindow();
var window3 = Ti.UI.createWindow();
var window4 = Ti.UI.createWindow();
var window5 = Ti.UI.createWindow();
var tab1 = Ti.UI.createTab({
	title: 'Tab 1',
	window: window1
});
var tab2 = Ti.UI.createTab({
	title: 'Tab 2',
	window: window2
});
var tab3 = Ti.UI.createTab({
	title: 'Tab 3',
	window: window3
});
var tab4 = Ti.UI.createTab({
	title: 'Tab 4',
	window: window4
});
var tab5 = Ti.UI.createTab({
	title: 'Tab 5',
	window: window5
});
var tabGroup = Titanium.UI.createTabGroup({
	tabs: [tab1, tab2, tab3, tab4, tab5]
});
tabGroup.addEventListener('open', function () {
	createTabView(window1);
	createTabView(window2);
	createTabView(window3);
	createTabView(window4);
	createTabView(window5);
});
tabGroup.open();
*Result:*
[ERROR] :  TiExceptionHandler: (main) [15051,20921] android.view.AbsSavedState$1 cannot be cast to android.widget.AbsListView$SavedState
[ERROR] :  TiExceptionHandler:
[ERROR] :  TiExceptionHandler:     android.widget.AbsListView.onRestoreInstanceState(AbsListView.java:1879)
[ERROR] :  TiExceptionHandler:     android.view.View.dispatchRestoreInstanceState(View.java:15633)
[ERROR] :  TiExceptionHandler:     android.view.ViewGroup.dispatchThawSelfOnly(ViewGroup.java:3288)
[ERROR] :  TiExceptionHandler:     android.widget.AdapterView.dispatchRestoreInstanceState(AdapterView.java:817)
[ERROR] :  TiExceptionHandler:     android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3274)
[ERROR] :  TiExceptionHandler:     android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3274)
[ERROR] :  TiExceptionHandler:     android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3274)
[ERROR] :  TiExceptionHandler:     android.view.View.restoreHierarchyState(View.java:15611)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.Fragment.restoreViewState(Fragment.java:415)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1454)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:792)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2215)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:649)
[ERROR] :  TiExceptionHandler:     android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:145)
[ERROR] :  TiExceptionHandler:     android.support.v4.view.ViewPager.populate(ViewPager.java:1238)
[ERROR] :  TiExceptionHandler:     android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:663)
[ERROR] :  TiExceptionHandler:     android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:625)
[ERROR] :  TiExceptionHandler:     android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:617)
[ERROR] :  TiExceptionHandler:     ti.modules.titanium.ui.widget.tabgroup.TiUIAbstractTabGroup.selectTab(TiUIAbstractTabGroup.java:312)
[ERROR] :  TiExceptionHandler:     ti.modules.titanium.ui.widget.tabgroup.TiUIBottomNavigationTabGroup.onMenuItemClick(TiUIBottomNavigationTabGroup.java:302)
[ERROR] :  TiExceptionHandler:     android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:167)
[ERROR] :  TiExceptionHandler:     android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:973)
[ERROR] :  TiExceptionHandler:     android.support.design.internal.BottomNavigationMenuView$1.onClick(BottomNavigationMenuView.java:95)
[ERROR] :  TiExceptionHandler:     android.view.View.performClick(View.java:5609)
[ERROR] :  TiExceptionHandler:     android.view.View$PerformClick.run(View.java:22259)
[ERROR] :  TiExceptionHandler:     android.os.Handler.handleCallback(Handler.java:751)
[ERROR] :  TiExceptionHandler:     android.os.Handler.dispatchMessage(Handler.java:95)
[ERROR] :  TiExceptionHandler:     android.os.Looper.loop(Looper.java:154)
[ERROR] :  TiExceptionHandler:     android.app.ActivityThread.main(ActivityThread.java:6077)
[ERROR] :  TiExceptionHandler:     java.lang.reflect.Method.invoke(Native Method)
[ERROR] :  TiExceptionHandler:     com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
[ERROR] :  TiExceptionHandler:     com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
*Cause:* This crash happens due to view ID collision as described by [TIMOB-17089] when a tab is being "restored" by the Android OS. Note that the view ID collision has been an issue before 8.0.0. The reason this tab selection crash regression is happening in 8.0.0 is due to the code refactoring where tabs are now implemented via a Java ViewPager whose default offscreen page limit is set to 1. This means the 8.0.0 TabGroup is only keep the tab on the left and the right of the current tab in memory. All other tabs are destroyed or are not created in memory until you tap on a tab farther in the group. Previously created destroyed tabs that are later "restored" cause the crash shown above. *Recommended Solution:* Resolve the [TIMOB-17089] issue by assigned unique IDs to all views to avoid collision. Also, we should bump up the ViewPager limit to a higher value to avoid the tab destroy/restore behavior so that they won't lose their current state.

Comments

  1. Rene Pot 2019-03-05

    Can you please define "random changes" and perhaps deliver a reproducible case we can use to test the crash with?
  2. Joshua Quick 2019-03-05

    By random changes, do you mean adding/removing tabs from the TabGroup while it is currently open? From look at the stack trace, a tab was selected either programmatically or it was tapped on, and then it crashed when Android attempted to restore the selected tab's "state". I'm curious if you are "removing" tabs dynamically?
  3. Joshua Quick 2019-03-05

    Also, what kind of views do you have in your tabs? For example, are you displaying a ListView? ti.map view?
  4. Andreas Pingas 2019-03-05

    Please check the following example. First click tab 4 and then tab 3
       
       
       function createDayView(e) {
       
       	var dayView = Titanium.UI.createView({
       		height:'80dip',
       		width:'66dip',
       		top:'0dip',
       		backgroundColor:'#FFF'
       	});
       	
       	var boxView = Titanium.UI.createView({
       		height:'56dip',
       		width:'56dip',
       		top:'10dip',
       		right:'10dip',
       		touchEnabled:false
       	});
       	
       	dayView.add(boxView);
       
       	var date = new Date(e.date);
       
       	var backgroundView = Ti.UI.createView({
       		height:'56dip',
       		width:'56dip',
       		borderRadius:'14dip',
       		backgroundColor:'#AAA',
       		touchEnabled:false
       	});
       	
       	boxView.add(backgroundView);
       
       	var verticalView = Ti.UI.createView({
       		height:Ti.UI.SIZE,
       		width:Ti.UI.SIZE,
       		layout:'vertical'
       	});
       	
       	boxView.add(verticalView);
       	
       	verticalView.add(Titanium.UI.createLabel({
       		height:Ti.UI.SIZE,
       		width:Ti.UI.SIZE,
       		text:date.getDate(),
       		ellipsize:Titanium.UI.TEXT_ELLIPSIZE_TRUNCATE_END,
       		textAlign:Titanium.UI.TEXT_ALIGNMENT_CENTER,	
       		verticalAlign:Titanium.UI.TEXT_VERTICAL_ALIGNMENT_CENTER,
       		font:{fontSize:'24sp', fontWeight:'bold', fontFamily:'Tahoma'},
       		color:'#FFF',
       		touchEnabled:false
       	}));
       	
       	verticalView.add(Titanium.UI.createLabel({
       		height:Ti.UI.SIZE,
       		width:Ti.UI.SIZE,
       		text:'OK',
       		horizontalWrap:false,
       		ellipsize:Titanium.UI.TEXT_ELLIPSIZE_TRUNCATE_END,
       		textAlign:Titanium.UI.TEXT_ALIGNMENT_CENTER,	
       		verticalAlign:Titanium.UI.TEXT_VERTICAL_ALIGNMENT_CENTER,
       		font:{fontSize:'10sp', fontWeight:'bold', fontFamily:'Tahoma'},
       		color:'#FFF',
       		touchEnabled:false
       	}));
       	
       	return(dayView);
       }
       
       function createMenuView(e) {
       		
       	var menuView = Titanium.UI.createView({
       		height:'80dip',
       		top:'0dip',
       		backgroundColor:'#FFF'
       	});
       		
       	var scrollView = Titanium.UI.createScrollView({
       		scrollType:'horizontal',
       		layout:'horizontal'
       	});
       	
       	menuView.add(scrollView);
       	
       	var dayViewData = [];
       
       	for (var i=0; i<12; i++) {
       		
       	 	var date = new Date();
       		date.setDate(date.getDate() + i);
       
       		var dayView = createDayView({
       			date:date
       		});
       
       		dayViewData.push(dayView);
       				
       		scrollView.add(dayView);
       		
       	}
       			
       	return(menuView);
       }
       
       function createTabView(win) {
       
       	var containerView = Titanium.UI.createView({
       		top:'80dip',
       		bottom:'0dip',
       		backgroundColor:'#FFF'
       	});
       	
       	win.add(containerView);
       	
       	var tableData = [];
       	
       	var menuView = createMenuView();
       	
       	win.add(menuView);
       			
       	var tableView = Titanium.UI.createTableView({
       		backgroundColor:'#FFF',
       		separatorStyle:Titanium.UI.TABLE_VIEW_SEPARATOR_STYLE_SINGLE_LINE,
       		tableSeparatorInsets:{left:'0dip', right:'0dip'}
       	});
       	
       	var section1 = Ti.UI.createTableViewSection();
       	var section2 = Ti.UI.createTableViewSection();
       
       	tableData.push(section1);
       	tableData.push(section2);
       	
       	tableView.data = tableData;
       	
       	containerView.add(tableView);
       	
       	var iconView = Titanium.UI.createView({
       		height:'60dip',
       		width:'60dip',
       		right:'25dip',
       		bottom:'25dip',
       		zIndex:100000
       	});
       			
       	iconView.add(Titanium.UI.createImageView({
       		height:'60dip',
       		width:'60dip',
       		touchEnabled:false
       	}));
       	
       	win.add(iconView);
       		
       };
       	
       var window1 = Ti.UI.createWindow();
       var window2 = Ti.UI.createWindow();
       var window3 = Ti.UI.createWindow();	
       var	window4 = Ti.UI.createWindow();
       var	window5 = Ti.UI.createWindow();
       
       var tab1 = Ti.UI.createTab({
       	title:'Tab 1',
       	window:window1
       });
       	
       var tab2 = Ti.UI.createTab({
       	title:'Tab 2',
       	window:window2
       });
       
       var tab3 = Ti.UI.createTab({
       	title:'Tab 3',
       	window:window3
       });
       
       var tab4 = Ti.UI.createTab({
       	title:'Tab 4',
       	window:window4
       });
       	
       var tab5 = Ti.UI.createTab({
       	title:'Tab 5',
       	window:window5
       });
       				
       var tabGroup = Titanium.UI.createTabGroup({
       	tabs:[tab1, tab2, tab3, tab4, tab5]
       });
       
       tabGroup.addEventListener('open', function() {
       	
       	createTabView(window1);
       	createTabView(window2);
       	createTabView(window3);
       	createTabView(window4);
       	createTabView(window5);
       
       });
         	
       tabGroup.open();
       
  5. Sharif AbuDarda 2019-03-06

    Hello [~andreas.pingas], I have tested your sample code provided above. I Wasn't able to reproduce the crash that you mentioned in the 8.0.0 Android emulator with SDK 7.5.1.GA. First, clicking tab 4 and then tab 3, nothing wrong happens. Where are you testing is it in the device (which version and model?) or in the emulator? Thanks.
  6. Andreas Pingas 2019-03-07

    Titanium SDK 8.0.0.RC Any Android version (Device or Emulator)
  7. Joshua Quick 2019-04-12

    PR (master): https://github.com/appcelerator/titanium_mobile/pull/10829
  8. Joshua Quick 2019-04-26

    PR (8.0.x): https://github.com/appcelerator/titanium_mobile/pull/10868
  9. Lokesh Choudhary 2019-04-26

    FR passed PR merged.
  10. Samir Mohammed 2019-04-29

    Closing ticket, fix verified in SDK version 8.0.1.v20190426162041 and SDK version 8.1.0.v20190426222341. Test and other information can be found at: Master : https://github.com/appcelerator/titanium_mobile/pull/10829 8_0_X: https://github.com/appcelerator/titanium_mobile/pull/10868

JSON Source