'Why doesn't my Android dynamic feature module's view have an id?
I'm seeing the following crash when inflating an Activity layout within a dynamic feature module:
Caused by: java.lang.IllegalStateException: FragmentContainerView must have an android:id to add Fragment com.example.MyFragment
at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:171)
The FragmentContainerView XML definitely does have an android:id attribute:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_host_view"
android:name="com.example.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
The launch flow looks like: Base App Module's MainActivity installs the dynamic feature module -> when feature module installation is complete, Base App Module's MainActivity calls startActivity() on an Activity within the feature module called FeatureActivity -> Feature Module's FeatureActivity.onCreate() tries to setContentView() with R.layout.activity_feature -> the activity_feature layout XML (only present in the feature module) throws inflation exception due to an IllegalStateException thrown by FragmentContainerView, as above.
The docs mention shenanigans related to resource and asset access across feature module boundaries, but I don't think that applies to my case since the resource id in question (fragment_host_view) is only accessed by FeatureActivity which is also part of the feature module. I have my main module's Application call SplitCompat.install(), and both MainActivity and FeatureActivity do the SplitCompat.installActivity() dance per the docs, but that doesn't seem to matter.
Looking at the referenced FragmentContainerView source suggests that the root problem is that my FragmentContainerView lost its view id from the XML somehow along the dynamic feature install flow; this error does not occur if I convert the dynamic feature module to a library module.
My FragmentContainerView is coming from androidx.fragment:fragment-ktx:1.3.6 and I'm testing using bundletool per the local test docs.
Why doesn't my FragmentContainerView have an id when it's inflated at runtime after dynamic feature installation?
Solution 1:[1]
This turned out to be a bug in FragmentContainerView https://issuetracker.google.com/issues/213086140?pli=1 caused by an assumption that valid view IDs would have a positive value when converted from hex to 32 bit signed integers, which is not always the case. IIRC, view IDs are assigned from the high byte of a 32 bit hex range, and being part of a dynamic feature module seems to bump the assigned ID values up significantly so you get into the overflow range when converting to signed 32 bit integer format, creating valid negative view IDs. The old FragmentContainerView was looking for ID > 0 so negative view IDs would fail and the error from my question above was the result.
This bug is fixed in Fragment module v1.4.1
Solution 2:[2]
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_host_view"
android:name="com.example.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
to
<fragment
android:id="@+id/fragment_host_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | CCJ |
Solution 2 | Meet Bhavsar |