flexbox-layout
flexbox-layout copied to clipboard
canScrollHorizontally() crashes if the RecyclerView is not attached to the Window
We have this use case where we might call recyclerView.smoothScrollToPosition
on a view that has been removed from its container. In that case, we get the following crash:
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getWidth()' on a null object reference
at com.google.android.flexbox.FlexboxLayoutManager.canScrollHorizontally(FlexboxLayoutManager.java:1900)
at com.google.android.flexbox.FlexboxLayoutManager.getChildWidthMeasureSpec(FlexboxLayoutManager.java:483)
at com.google.android.flexbox.FlexboxHelper.calculateFlexLines(FlexboxHelper.java:458)
at com.google.android.flexbox.FlexboxHelper.calculateHorizontalFlexLines(FlexboxHelper.java:243)
at com.google.android.flexbox.FlexboxLayoutManager.updateFlexLines(FlexboxLayoutManager.java:955)
at com.google.android.flexbox.FlexboxLayoutManager.onLayoutChildren(FlexboxLayoutManager.java:731)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1858)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5044)
Sample code to reproduce the issue => https://github.com/martinbonnin/FlexboxTest. It mainly boils down to:
val recyclerView = RecyclerView(this)
recyclerView.layoutManager = FlexboxLayoutManager(this)
recyclerView.adapter = object: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
[....]
}
recyclerView.smoothScrollToPosition(500)
I understand scrolling on a non-visible View is not the most useful thing to do but I would still expect the LayoutManager to handle this case gracefully ?
I'm seeing a very similar crash when I try to nest RecyclerView
s with FlexboxLayoutManager
s. If I use FlexboxLayoutManager
for the top-level RecyclerView
and LinearLayoutManager
for the inner RecyclerView
s, everything works fine. But when I change the inner layout manager to be a FlexboxLayoutManager
, I get this in the logs:
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getHeight()' on a null object reference
at com.google.android.flexbox.FlexboxLayoutManager.canScrollVertically(FlexboxLayoutManager.java:1903)
at com.google.android.flexbox.FlexboxLayoutManager.getChildHeightMeasureSpec(FlexboxLayoutManager.java:491)
at com.google.android.flexbox.FlexboxHelper.calculateFlexLines(FlexboxHelper.java:478)
at com.google.android.flexbox.FlexboxHelper.calculateVerticalFlexLines(FlexboxHelper.java:318)
at com.google.android.flexbox.FlexboxLayoutManager.updateFlexLines(FlexboxLayoutManager.java:970)
at com.google.android.flexbox.FlexboxLayoutManager.onLayoutChildren(FlexboxLayoutManager.java:729)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3336)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.cardview.widget.CardView.onMeasure(CardView.java:260)
at android.view.View.measure(View.java:18788)
at com.google.android.flexbox.FlexboxHelper.calculateFlexLines(FlexboxHelper.java:483)
at com.google.android.flexbox.FlexboxHelper.calculateVerticalFlexLines(FlexboxHelper.java:318)
at com.google.android.flexbox.FlexboxLayoutManager.updateFlexLines(FlexboxLayoutManager.java:970)
at com.google.android.flexbox.FlexboxLayoutManager.onLayoutChildren(FlexboxLayoutManager.java:729)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
Also relevant is that the inner RecyclerView
is using wrap_content
for its dimensions. If I use a constant size for both dimensions, the crash disappears (though I can't scroll the contents of the inner RecyclerView
s).
Incidentally, I'm using inner RecyclerView
+ FlexboxLayoutManager
instead of a FlexboxLayout
for each of the outer-level items so that I can use a shared RecycledViewPool
.
Hi @martinbonnin,
Thanks for the report. I checked your repository, but the activity_main only has a top-level ConstraintLayout.
And the app didn't crash when I launched the app. Could you confirm if the app really crashes?
@thagikura thanks for looking into this. The crash happens on a Nexus 9 tablet with Android 6.0. I tried to reproduce on a Pixel 3 XL but the crash did not happen indeed. So I guess it depends the framework version :-/.
main_activity.xml is really empty on purpose, the trick is to create a RecyclerView programmatically and not attach it to any parent.
I'm seeing a very similar crash when I try to nest
RecyclerView
s withFlexboxLayoutManager
s. If I useFlexboxLayoutManager
for the top-levelRecyclerView
andLinearLayoutManager
for the innerRecyclerView
s, everything works fine. But when I change the inner layout manager to be aFlexboxLayoutManager
, I get this in the logs:java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getHeight()' on a null object reference at com.google.android.flexbox.FlexboxLayoutManager.canScrollVertically(FlexboxLayoutManager.java:1903) at com.google.android.flexbox.FlexboxLayoutManager.getChildHeightMeasureSpec(FlexboxLayoutManager.java:491) at com.google.android.flexbox.FlexboxHelper.calculateFlexLines(FlexboxHelper.java:478) at com.google.android.flexbox.FlexboxHelper.calculateVerticalFlexLines(FlexboxHelper.java:318) at com.google.android.flexbox.FlexboxLayoutManager.updateFlexLines(FlexboxLayoutManager.java:970) at com.google.android.flexbox.FlexboxLayoutManager.onLayoutChildren(FlexboxLayoutManager.java:729) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924) at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3336) at android.view.View.measure(View.java:18788) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465) at android.widget.LinearLayout.measureVertical(LinearLayout.java:748) at android.widget.LinearLayout.onMeasure(LinearLayout.java:630) at android.view.View.measure(View.java:18788) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at androidx.cardview.widget.CardView.onMeasure(CardView.java:260) at android.view.View.measure(View.java:18788) at com.google.android.flexbox.FlexboxHelper.calculateFlexLines(FlexboxHelper.java:483) at com.google.android.flexbox.FlexboxHelper.calculateVerticalFlexLines(FlexboxHelper.java:318) at com.google.android.flexbox.FlexboxLayoutManager.updateFlexLines(FlexboxLayoutManager.java:970) at com.google.android.flexbox.FlexboxLayoutManager.onLayoutChildren(FlexboxLayoutManager.java:729) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924) at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641) at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
Also relevant is that the inner
RecyclerView
is usingwrap_content
for its dimensions. If I use a constant size for both dimensions, the crash disappears (though I can't scroll the contents of the innerRecyclerView
s).Incidentally, I'm using inner
RecyclerView
+FlexboxLayoutManager
instead of aFlexboxLayout
for each of the outer-level items so that I can use a sharedRecycledViewPool
.
have you managed to solve this issue? I'm getting the same.
@bgorkowy I workaround'd the issue for now
A workaround is to clone the library and perform a check on line 1901
@Override public boolean canScrollHorizontally() { if (mFlexWrap == FlexWrap.NOWRAP) { return isMainAxisDirectionHorizontal(); } else { return !isMainAxisDirectionHorizontal() || getWidth() > (mParent != null ? mParent.getWidth() : 0); } }
I created a PR for the fix here