Last Modified:
The specified child already has a parent. You must call removeView() on the child's parent first.
#NativeScript
tns-core-modules 6.1.2 で直っているかも。 fix(frame-android): IllegalStateException: The specified child already has a parent by manoldonev · Pull Request #7948 · NativeScript/NativeScript
- tns-core-modules 6.1.0
- tns-android 6.1.2
問題
BottomNavigation を使った android アプリケーションで HMR(Hot Module Replacement) を使うと例外が発生する場合がある。
System.err: An uncaught Exception occurred on "main" thread.
System.err: Calling js method run failed
System.err: Error: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
System.err: android.view.ViewGroup.addViewInner(ViewGroup.java:5034)
System.err: android.view.ViewGroup.addView(ViewGroup.java:4865)
...
System.err:
System.err: StackTrace:
System.err: push.../node_modules/tns-core-modules/ui/bottom-navigation/bottom-navigation.js.BottomNavigation.commitCurrentTransaction(file:///node_modules/tns-core-modules/ui/bottom-navigation/bottom-navigation.js:327:0)
System.err: at push.../node_modules/tns-core-modules/ui/bottom-navigation/bottom-navigation.js.BottomNavigation.changeTab(file:///node_modules/tns-core-modules/ui/bottom-navigation/bottom-navigation.js:341:0)
System.err: at push.../node_modules/tns-core-modules/ui/bottom-navigation/bottom-navigation.js.BottomNavigation.onLoaded(file:///node_modules/tns-core-modules/ui/bottom-navigation/bottom-navigation.js:267:0)
System.err: at (file:///node_modules/tns-core-modules/ui/core/view-base/view-base.js:312:75)
...
原因
原因ははっきり分からないけれど、 BottomNavigation#{selectedIndex!=0} => TabContentItem => Frame => Page
の構造があるときに発生することを確認。
<BottomNavigation selectedIndex="1" xmlns="http://schemas.nativescript.org/tns.xsd">
<TabStrip>
<TabStripItem>
<Label text="0"/>
</TabStripItem>
<TabStripItem>
<Label text="1"/>
</TabStripItem>
</TabStrip>
<TabContentItem>
<Frame defaultPage="page0" />
</TabContentItem>
<TabContentItem>
<Frame defaultPage="page1" />
</TabContentItem>
</BottomNavigation>
BottomNavigation => TabContentItem => Page
では発生しないBottomNavigation#{selectedIndex=0}
では発生しない
HMR 後に表示中のページ({selectedIndex!=0})をもう一度表示させようとしたときに selectedIndexChangedEvent がガチャガチャ飛んで、例外が発生している感じ。
tns-core-modules/ui/frame/frame.android.js#reloadPage
あたりで、表示中の Frame が正しく解放されてないんじゃないかと思うけど、解決できなかった。
解決(応急処置)
BottomNavigation#onLoaded の前後で selectedIndex=0 → selectedIndex=選択したいタブ
とすれば例外は発生しなくなったのでとりあえずこれで。
if (bottomNavigation.android) {
if (!BottomNavigation.prototype['onLoadedOverridden']) {
let lastSelectedIndex = 0;
BottomNavigation.prototype['_onRootViewResetOverridden'] = BottomNavigation.prototype._onRootViewReset;
BottomNavigation.prototype._onRootViewReset = function () {
lastSelectedIndex = this.selectedIndex;
return BottomNavigation.prototype['_onRootViewResetOverridden'].call(this);
}
BottomNavigation.prototype['onLoadedOverridden'] = BottomNavigation.prototype.onLoaded;
BottomNavigation.prototype.onLoaded = function () {
if (this._attachedToWindow) {
this.selectedIndex = 0;
}
const retVal = BottomNavigation.prototype['onLoadedOverridden'].call(this);
if (this._attachedToWindow) {
this.selectedIndex = lastSelectedIndex;
}
return retVal;
};
}
}