2

I am trying to add a simple scroll bar to my RecyclerView. I have found two suggestions on how to do this, but neither have given me results. These suggestions are setting the orientation of the LayoutManager to VERTICAL and/or adding the android:scrollbars="vertical" attribute to the RecyclerView. The first method does not show a scroll bar, and the second crashes the application, with a NullPointerException:

12-14 16:39:09.392 31768-31768/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.example.app, PID: 31768
        java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$LayoutManager.canScrollVertically()' on a null object reference
            at android.support.v7.widget.RecyclerView.computeVerticalScrollRange(RecyclerView.java:1654)
            at android.view.View.onDrawScrollBars(View.java:13924)
            at android.view.View.onDrawForeground(View.java:17657)
            at android.view.View.draw(View.java:16189)
            at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3097)
            at android.view.View.updateDisplayListIfDirty(View.java:15174)
            at android.view.View.draw(View.java:15948)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
            at android.view.View.updateDisplayListIfDirty(View.java:15169)
            at android.view.View.draw(View.java:15948)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
            at android.view.View.updateDisplayListIfDirty(View.java:15169)
            at android.view.View.draw(View.java:15948)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
            at android.view.View.updateDisplayListIfDirty(View.java:15169)
            at android.view.View.draw(View.java:15948)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
            at android.view.View.updateDisplayListIfDirty(View.java:15169)
            at android.view.View.draw(View.java:15948)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
            at android.view.View.updateDisplayListIfDirty(View.java:15169)
            at android.view.View.draw(View.java:15948)
            at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
            at android.view.View.draw(View.java:16181)
            at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2690)
            at android.view.View.updateDisplayListIfDirty(View.java:15174)
            at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:281)
            at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:287)
            at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:322)
            at android.view.ViewRootImpl.draw(ViewRootImpl.java:2615)
            at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2434)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2067)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
            at android.view.Choreographer.doCallbacks(Choreographer.java:670)
            at android.view.Choreographer.doFrame(Choreographer.java:606)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

This is my code for initializing the RecyclerView, which works fine as long as I do not have the attribute android:scrollbars="vertical", but does not show a scroll bar:

LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
layoutManager.setSmoothScrollbarEnabled(true);

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new DividerDecoration(this));
recyclerView.setAdapter(new MyAdapter(dataset));

Am I doing something wrong? Is there a simpler way to get scroll bars for a RecyclerView?


This is the XML, just a simple RecyclerView in a FrameLayout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView android:id="@+id/recycler"
            android:layout_width="match_parent" android:layout_height="match_parent">
            <!--android:scrollbars="vertical"-->
</FrameLayout>
Community
  • 1
  • 1
Bryan
  • 14,756
  • 10
  • 70
  • 125

1 Answers1

4

I found the problem, though still not the result I was hoping for. Turns out it was because I was initializing the RecyclerView after onCreate(), therefore the content view would skip the RecyclerView because there is no adapter attached. Then when the RecyclerView tries to call LayoutManager.canScrollVertically(), because of the attribute android:scrollbars="vertical", it gets a NullPointerException because there is no LayoutManager attached.

The solution is to initialize the RecyclerView in onCreate() with a null Adapter, then swap the Adapter when I receive the data. Something like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recycler);

    mRecycler = (RecyclerView) findViewById(R.id.recycler);

    mRecycler.setLayoutManager(new LinearLayoutManager(this));
    mRecycler.setHasFixedSize(true);
    mRecycler.addItemDecoration(new DividerDecoration(this));
    mRecycler.addAdapter(new MyAdapter(null));

    new MyTask(this).execute;
}

@Override
protected void onPostExecute(ArrayList<Data> dataset) {
    mRecycler.swapAdapter(new MyAdapter(dataset), false);
}

This enables the scrollbar set with android:scrollbars="vertical", but I was hoping for a persistent scrollbar that the user can interact with, not just a visual indicator.

Bryan
  • 14,756
  • 10
  • 70
  • 125
  • Thanks - for me this works with just putting the "setLayoutManager" in the Create. Everything else is unnecessary – Kibi Feb 16 '16 at 12:36