[TIMOB-26890] Android: Switch between TabGroup tabs 1 and 4 sometimes crashes the app as of 8.0.0
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Critical |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2019-04-29T14:43:17.000+0000 |
Affected Version/s | Release 8.0.0 |
Fix Version/s | Release 8.0.1 |
Components | Android |
Labels | TabGroup, android, engSchedule, regression |
Reporter | Andreas Pingas |
Assignee | Joshua Quick |
Created | 2019-03-05T12:23:44.000+0000 |
Updated | 2019-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.
Can you please define "random changes" and perhaps deliver a reproducible case we can use to test the crash with?
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?Also, what kind of views do you have in your tabs? For example, are you displaying a
ListView
?ti.map
view?Please check the following example. First click tab 4 and then tab 3
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.
Titanium SDK 8.0.0.RC Any Android version (Device or Emulator)
PR (master): https://github.com/appcelerator/titanium_mobile/pull/10829
PR (8.0.x): https://github.com/appcelerator/titanium_mobile/pull/10868
FR passed PR merged.
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