Status Update
Comments
ja...@google.com <ja...@google.com>
il...@google.com <il...@google.com> #2
Branch: androidx-main
commit 57ca221882695bd6a52549f4d9ea3b812e6fe87c
Author: Simon Schiller <simonschiller@users.noreply.github.com>
Date: Mon Mar 22 16:09:30 2021
[GH] [FragmentStrictMode] Detect <fragment> tag usage
## Proposed Changes
- Detect `<fragment>` tag usage inside XML layouts
## Testing
Test: See `FragmentStrictModeTest#detectFragmentTagUsage`
## Issues Fixed
Fixes: 153738235
This is an imported pull request from
Resolves #141
Github-Pr-Head-Sha: 4ea052596e4341b9f11bcf335e2bc38045a91f19
GitOrigin-RevId: 62e7487aa4874eef6bb556490e193717cf937251
Change-Id: Iae48578e85e4e4897f806d7ade2e2a660adf9479
M fragment/fragment/api/public_plus_experimental_current.txt
M fragment/fragment/api/restricted_current.txt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/strictmode/FragmentStrictModeTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
M fragment/fragment/src/main/java/androidx/fragment/app/strictmode/FragmentStrictMode.java
A fragment/fragment/src/main/java/androidx/fragment/app/strictmode/FragmentTagUsageViolation.java
il...@google.com <il...@google.com> #3
It seems like this is a similar case to LayoutInflater
is being used. This causes FragmentContainerView
to use the activity's FragmentManager rather than the childFragmentManager
(which it absolutely should use for nested Fragments). In these cases, the <fragment>
tag was just always doing the wrong thing, leading to a host of issues when it comes to recreate the fragment's state correctly.
Unfortunately, for the DialogFragment
case, getting the correct LayoutInflater
is a bit trickier due to PreferenceDialogFragmentCompat
to use getLayoutInflater()
instead of its current usage of LayoutInflater.from(context)
.
Since the <fragment>
tag is silently doing the wrong thing, I still can't recommend that you use it. The correct workaround would involve subclassing PreferenceDialogFragmentCompat
and overriding its onCreateDialogView
method to add the Fragment to the FragmentContainerView
via childFragmentManager.beginTransaction()
instead of using android:name
/class
in your XML.
[Deleted User] <[Deleted User]> #4
The fragment is added in layout_with_fragment.xml, and used in CustomDialogPreference.kt
Here I used the <fragment> tag which doesn't cause an FC. If the <fragment> tag found in layout_with_fragment.xml is replaced with <androidx.fragment.app.FragmentContainerView>, the application will crash and put out the stackTrace as posted above.
Thank you for the detailed explanation. Please let me know if you need more information or if I was unclear.
ap...@google.com <ap...@google.com> #5
Branch: androidx-master-dev
commit 49bd23aeb52f5975d60c1dbb7cf0318bffee6e35
Author: Jeremy Woods <jbwoods@google.com>
Date: Wed Mar 11 18:58:54 2020
Use correct layout inflater in PreferenceDialogFragment
In onCreateDialogView() PreferenceDialogFragment uses the wrong
LayoutInflater to inflate the DialogView. Instead of the layout inflater
from the context, it should use its own layout inflater (which is
correct since aosp/1253912).
Test: added PreferenceDialogFragmentCompat
Bug: 150051716
RelNote: "PreferenceDialogFragmentCompat will no longer throw an
IllegalStateException when inflating a FragmentContainerView from xml."
Change-Id: I6eb6031eb7d0ab1f442d8c1b7463c727089fbf20
M preference/preference/build.gradle
A preference/preference/src/androidTest/java/androidx/preference/tests/PreferenceDialogFragmentCompatTest.kt
A preference/preference/src/androidTest/res/layout/inflated_fragment_container_view.xml
A preference/preference/src/androidTest/res/layout/inflated_fragment_tag.xml
A preference/preference/src/androidTest/res/layout/simple_layout.xml
A preference/preference/src/androidTest/res/xml/test_fragment_container_dialog_preference.xml
A preference/preference/src/androidTest/res/xml/test_fragment_tag_dialog_preference.xml
M preference/preference/src/main/java/androidx/preference/PreferenceDialogFragmentCompat.java
jb...@google.com <jb...@google.com> #6
This has been fixed internally and will be available in the Preference 1.1.1 release.
Description
When I replace the <fragment> tag with <androidx.fragment.app.FragmentContainerView> as lint suggests and I click the DialogPreference, it results in a crash. (stack trace posted below)
I'll happily provide some code snippets if necessary.
android.view.InflateException: Binary XML file line #7: Binary XML file line #7: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: java.lang.IllegalStateException: FragmentManager is already executing transactions
at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1778)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1814)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:166)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:51)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:335)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at androidx.preference.PreferenceDialogFragmentCompat.onCreateDialogView(PreferenceDialogFragmentCompat.java:228)
at androidx.preference.PreferenceDialogFragmentCompat.onCreateDialog(PreferenceDialogFragmentCompat.java:147)
at androidx.fragment.app.DialogFragment.onGetLayoutInflater(DialogFragment.java:403)
at androidx.fragment.app.Fragment.performGetLayoutInflater(Fragment.java:1484)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)