androidandroid-recyclerviewandroid-view

Why does RecyclerView.canScrollVertically occasionally throw "Attempt to invoke virtual method ...View.getLayoutParams()' on a null object reference"?


Layout:

<RelativeLayout
    android:id="@+id/relativeLayoutMain"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="200"
    android:gravity="center">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="0dp"
        android:horizontalSpacing="0dp"
        android:numColumns="2"
        android:stretchMode="columnWidth"
        android:verticalSpacing="0dp" />
</RelativeLayout>

Java code:

RecyclerView recyclerView = findViewById(R.id.recyclerView);
if (recyclerView.canScrollVertically(1) || recyclerView.canScrollVertically(-1)) {
   //do something
} 

This works fine usually. App analytics occasionally reports the following exception:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.ViewGroup$LayoutParams android.view.View.getLayoutParams()' on a null object reference
        at androidx.recyclerview.widget.RecyclerView$LayoutManager$2.getChildStart(RecyclerView.java:8573)
        at androidx.recyclerview.widget.ViewBoundsCheck.findOneViewWithinBoundFlags(ViewBoundsCheck.java:219)
        at androidx.recyclerview.widget.LinearLayoutManager.findOneVisibleChild(LinearLayoutManager.java:2125)
        at androidx.recyclerview.widget.LinearLayoutManager.findFirstVisibleChildClosestToEnd(LinearLayoutManager.java:1900)
        at androidx.recyclerview.widget.LinearLayoutManager.computeScrollOffset(LinearLayoutManager.java:1264)
        at androidx.recyclerview.widget.LinearLayoutManager.computeVerticalScrollOffset(LinearLayoutManager.java:1230)
        at androidx.recyclerview.widget.GridLayoutManager.computeVerticalScrollOffset(GridLayoutManager.java:1920)
        at androidx.recyclerview.widget.RecyclerView.computeVerticalScrollOffset(RecyclerView.java:2481)
        at android.view.View.canScrollVertically(View.java:17448)

Could anyone shed some light on the possible causes?

I'd like to emphasize that the code works fine 99+% of the time.


Solution

  • You shouldn't be using that function. Try calling canScrollVertically() on the layout manager (note no direction parameter). That function seems to be doing a lot more work than is needed, calculating sizes. My guess is it has some race conditions in it.

    Also, make sure you only call this on the UI thread. Doing it on another would definitely risk race conditions with recycling of views.