Status Update
Comments
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
[Deleted User] <[Deleted User]> #3
I updated Fragment to 1.3.2, but I still get this crash.
[Deleted User] <[Deleted User]> #4
I can confirm it with Firebase Crashlytics, but I do not know the condition of occurrence yet, and there is no sample project yet.
eu...@gmail.com <eu...@gmail.com> #5
eu...@gmail.com <eu...@gmail.com> #6
```
java.lang.NullPointerException: Attempt to invoke virtual method 'float android.view.View.getAlpha()' on a null object reference
at androidx.fragment.app.SpecialEffectsController$Operation$State.from(SpecialEffectsController$Operation.java:409)
at androidx.fragment.app.SpecialEffectsController.markPostponedState(SpecialEffectsController.java:236)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2201)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:873)
```
il...@google.com <il...@google.com> #7
Re #5 - if you have a sample project that reproduces this issue, we'd be happy to take a look.
eu...@gmail.com <eu...@gmail.com> #8
eu...@gmail.com <eu...@gmail.com> #9
[Deleted User] <[Deleted User]> #10
Looking at BugSnag breadcrumbs, the crash always occurs immediately after a Fragment is destroyed. Not always the same fragment... I'm seeing a variety of fragments, which I suspect correspond to our most-used features.
Timing of the earliest occurrences of this crash seem to line up with our having upgraded androidx.fragment:fragment-ktx from 1.2.5 to 1.3.3, but I have no strong evidence this is the cause.
eu...@gmail.com <eu...@gmail.com> #11
[Deleted User] <[Deleted User]> #12
Thank you, I'll try it.
[Deleted User] <[Deleted User]> #13
jb...@google.com <jb...@google.com> #14
You can only get here if your fragment has a view and the from
method where this error happens doesn't even take null
views (from
, not when the view calls getAlpha()
.
It is clear that the fragment definitely starts off with a view, but that view is removed prematurely by something. The only place fragments every clear out the view is when it is destroyed. Is is possible that your app is clearing the fragment view somewhere? It would be nice if we had some fragment manager logging to see what is actually going on, but without more information there isn't much we can figure out.
ma...@gmail.com <ma...@gmail.com> #15
I was able to generate logs for activity leading up to the crash. See attached. (I am now able to reproduce the crash reliably within our application. I have not had time to prepare a standalone project that reproduces the crash.)
Meanwhile, I'll take a closer look at our Fragment-management code to see if we're clearing the fragment view somewhere. Thanks for the guidance on what might be happening here.
jb...@google.com <jb...@google.com> #16
Based off of the logs we were able to identify the issue and get a fix.
Somewhere in the app you are popping the add of your GamecastFragment
causing a remove and then attempting to do a hide()
on the same fragment you just removed:
fm.beginTransaction()
.hide(fragment1)
.add(R.id.content, fragment2)
.addToBackStack(null)
.commit()
... sometime later
fm.popBackStack()
fm.beginTransaction()
.hide(fragment2)
.show(fragment1)
.addToBackStack(null)
.commit()
This is an issue because the popBackStack()
kicks of the exit transition and then immediately after that the hide is enqueued. Now you have a currently removing fragment that the FragmentManager
is preparing to hide. Since the hide is the last thing it sees, it doesn't know that the fragment is actually being removed and to ignore the hide until the remove is complete, so the states get mixed up and the view is destroyed. Had the app been using setReorderAllowed(true)
on all of the transactions, the pop and last transactions would have been combined together and the FragmentManager
would have calculated the final state and been able to avoid this. That being said it is unlikely that this behavior is actually intended cause hiding the view of a fragment that has been removed doesn't do anything.
[Deleted User] <[Deleted User]> #17
I confirmed your findings. We have a hide that occurs earlier in code, which I think is there as a blanket measure to make sure that the fragment "behind" the fragment we're about to add doesn't remain visible:
final Fragment primaryFragment = fragmentManager.getPrimaryNavigationFragment();
if (primaryFragment != null) {
fragmentTransaction
.hide(primaryFragment);
}
In the scenario where we end up using popBackStack(primaryFragment.getTag(), FragmentManager.POP_BACK_STACK_INCLUSIVE)
as part of our code to show the existing fragment, this hide is unnecessary. If I simply remove it, the crash goes away. If I call setReorderingAllowed(true)
on the transaction, that also eliminates the crash and retains the desired effect.
I'm curious how you plan to address this, since this shouldn't lead to a NullPointerException
. The hardest part about this crash is that our own code appears nowhere in the stack trace, making it very challenging to track down its cause when we see crash reports "in the wild". If this is an invalid combination & order of actions for a transaction, we would ideally find out via an IllegalStateException
or something similar at the time we attempt to commit the transaction. But I can imagine that kind of validation at the time of commit could be costly. Perhaps it makes sense to discard the hide
in this scenario?
Thanks for helping to understand what's going on here! This gives me a much better solution than turning off the new fragment management entirely.
ap...@google.com <ap...@google.com> #18
Branch: androidx-main
commit 907810e8c9f6b2610ce479713f2d5afec0511103
Author: Jeremy Woods <jbwoods@google.com>
Date: Thu Jun 03 18:12:03 2021
Fix conflicts between remove by pop and hide
If you do an add, then call popBackStack() and commit a transaction to
hide the same fragment is being removed by the pop while using
transitions and not using `reorderingAllowed(true)`, the fragment
manager will end up destroying the view of the fragment too early. The
reason for this is that the pop will start the transition of the remove,
but before the remove is complete, the hide operation is enqueued and
causes the computed state of the fragment to be incorrect and that
results in the view being destroyed.
While hiding a removed fragment is not something you actually probably
want to do, we should make sure this at least doesn't crash.
Instead of relying solely on the new pending operations to determine the
state of the fragment, if the pending operation does not affect the
Lifecycle (i.e. it is a show or hide), we should also consider the
lifecycle impact of the running operation as well.
RelNote: "The `FragmentManager` will no longer crash when you attempt to
hide a removing fragment."
Test: testPopRemoveWithHide()
Bug: 183634730
Change-Id: I573ddcfcd1b9c782b5546dd4643e0e4ed042b277
M fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
jb...@google.com <jb...@google.com> #19
This has been fixed internally and will be part of the Fragment 1.4.0-alpha03
release.
pa...@irisconnect.co.uk <pa...@irisconnect.co.uk> #20
da...@yit.co.il <da...@yit.co.il> #21
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'float android.view.View.getAlpha()' on a null object reference
at androidx.fragment.app.SpecialEffectsController$Operation$State.from(SpecialEffectsController.java:430)
at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:62)
at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:306)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1853)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1764)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1701)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:488)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8663)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
[Deleted User] <[Deleted User]> #22
updated version 1.5.0 not fixed this.
java.lang.NullPointerException: Attempt to invoke virtual method 'float android.view.View.getAlpha()' on a null object reference at androidx.fragment.app.SpecialEffectsController$Operation$State.from(SpecialEffectsController.java:430) at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:62) at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:306) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1903) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1808) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1751) at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:538) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7870) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
mr...@gmail.com <mr...@gmail.com> #23
il...@google.com <il...@google.com> #24
Re
hy...@gmail.com <hy...@gmail.com> #25
java.lang.NullPointerException: Attempt to invoke virtual method 'float android.view.View.getAlpha()' on a null object reference
at androidx.fragment.app.SpecialEffectsController$Operation$State.from(SpecialEffectsController.java:430)
at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:62)
at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:306)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1912)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1817)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1760)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:547)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8653)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
il...@google.com <il...@google.com> #26
Re
tu...@gmail.com <tu...@gmail.com> #27
Fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'float android.view.View.getZ()' on a null object reference
android.view.ViewGroup.buildOrderedChildList (ViewGroup.java:4658)
android.view.ViewGroup.dispatchDraw (ViewGroup.java:4483)
android.view.View.draw (View.java:24409)
androidx.recyclerview.widget.RecyclerView.draw (RecyclerView.java:4603)
android.view.View.buildDrawingCacheImpl (View.java:23664)
android.view.View.buildDrawingCache (View.java:23524)
android.view.View.updateDisplayListIfDirty (View.java:23235)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ViewGroup.recreateChildDisplayList (ViewGroup.java:4732)
android.view.ViewGroup.dispatchGetDisplayList (ViewGroup.java:4704)
android.view.View.updateDisplayListIfDirty (View.java:23214)
android.view.ThreadedRenderer.updateViewTreeDisplayList (ThreadedRenderer.java:777)
android.view.ThreadedRenderer.updateRootDisplayList (ThreadedRenderer.java:783)
android.view.ThreadedRenderer.draw (ThreadedRenderer.java:881)
android.view.ViewRootImpl.draw (ViewRootImpl.java:5647)
android.view.ViewRootImpl.performDraw (ViewRootImpl.java:5330)
android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:4486)
android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:3116)
android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:10885)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1301)
android.view.Choreographer$CallbackRecord.run (Choreographer.java:1309)
android.view.Choreographer.doCallbacks (Choreographer.java:923)
android.view.Choreographer.doFrame (Choreographer.java:852)
android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1283)
android.os.Handler.handleCallback (Handler.java:942)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8757)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
[Deleted User] <[Deleted User]> #28
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'float android.view.View.getAlpha()' on a null object reference
at androidx.fragment.app.SpecialEffectsController$Operation$State.from(SpecialEffectsController.java:412)
at androidx.fragment.app.DefaultSpecialEffectsController.executeOperations(DefaultSpecialEffectsController.java:62)
at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController.java:297)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2202)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8757)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Description
Component used: Fragment Version used:1.3.1 Devices/Android versions reproduced on:Xperia XZ1
If this is a bug in the library, we would appreciate if you could attach: