Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

canScrollHorizontally() crashes if the RecyclerView is not attached to the Window #474

Open
martinbonnin opened this issue Dec 6, 2018 · 6 comments

Comments

@martinbonnin
Copy link

martinbonnin commented Dec 6, 2018

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 ?

@zizibaloob
Copy link

I'm seeing a very similar crash when I try to nest RecyclerViews with FlexboxLayoutManagers. If I use FlexboxLayoutManager for the top-level RecyclerView and LinearLayoutManager for the inner RecyclerViews, 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 RecyclerViews).

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.

@thagikura
Copy link
Contributor

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?

@martinbonnin
Copy link
Author

@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.

@bgorkowy
Copy link

I'm seeing a very similar crash when I try to nest RecyclerViews with FlexboxLayoutManagers. If I use FlexboxLayoutManager for the top-level RecyclerView and LinearLayoutManager for the inner RecyclerViews, 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 RecyclerViews).

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.

have you managed to solve this issue? I'm getting the same.

@martinbonnin
Copy link
Author

@bgorkowy I workaround'd the issue for now

@KryptKode
Copy link
Contributor

KryptKode commented Apr 19, 2019

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

KryptKode added a commit to KryptKode/flexbox-layout that referenced this issue Apr 19, 2019
thagikura pushed a commit that referenced this issue Sep 11, 2019
* Fixed issue 474, canScrollHorizontally() throws NPE if the RecyclerView is not attached to the Window
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants