Gil Moshayof Gil Moshayof - 2 months ago 8
Java Question

Android RecyclerView - clearOldPositions - NullPointerExceptions

I've run into a very strange issue using the

RecyclerView
from the support package.

I have a
RecyclerView
inside a
ViewPager
. The moment the
ViewPager
shows the
RecyclerView
, the app crashes with the following stack trace:

java.lang.NullPointerException
at android.support.v7.widget.RecyclerView.clearOldPositions(RecyclerView.java:2378)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1968)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
at android.widget.ScrollView.onLayout(ScrollView.java:1468)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1594)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1055)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1055)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:890)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
at android.view.View.layout(View.java:14817)
at android.view.ViewGroup.layout(ViewGroup.java:4631)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1987)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1744)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:544)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)


I can't find any sources about this on the internet, so if anyone's run into this before, any help would be appreciated.

Some background:

I'm importing the RecyclerView inside the build.gradle like so:

compile 'com.android.support:recyclerview-v7:+'


I'm setting the Adapter and LayoutManager to the RecyclerView inside the RecyclerView's constructor like so:

public CategoryParallaxView(Context context)
{
super(context);
init();
}

public CategoryParallaxView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}

public CategoryParallaxView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}

private void init()
{
mLayoutManager = new CategoryParallaxLayoutManager();
setLayoutManager(mLayoutManager);

mCategoryList = new ArrayList<CartCategory>();
mAdapter = new CategoryParallaxAdapter();
setAdapter(mAdapter);
}


When the
RecyclerView
is displayed, the size of the datasource (
mCategoryList
) is 0, but the list itself is not null.

The
RecyclerView
is nested inside a LinearLayout (which itself is nested inside a ScrollView), and has
MATCH_PARENT
defined in width and height. From some debugging, it seems like the width and height calculated for the
RecyclerView
are correct.

Not sure if this is relevant, but in my implementation, the
Adapter
,
ViewHolder
and
LayoutManager
subclasses are all private inner-classes of the my
RecyclerView
subclass.

Answer

The problem was that the RecyclerView was clearing the LayoutManager that I was setting in the init method the moment the RecyclerView became visible in the ViewPager.

I fixed this by assigning the LayoutManager immediately after the RecyclerView became visible. It feels a bit hacky, but I can't find any other work around. If anyone can find a better solution, please post.