Why am I getting a null reference on my RecyclerView
It seems that If you have a RecyclerView in your layout and you load it in the Activity, it is a must to set a LayoutManager for it, else it will throw this Exception when trying to destroy it. I have just experienced this error and this is the way I've solved it:
My activity showed elements in a pair of TextViews or in a RecyclerView depending on the amount of items: if it was a collection of items, I used the RecyclerView; if there was only one item, it was displayed on the TextViews and I set the RecyclerView's visibility to GONE
.
Then, in the first case, I called myRecyclerView.setLayoutManager(myLayoutManager)
, but in the other case I didn't, for I wasn't going to use it. In both cases, the Activity containing the RecyclerView was displayed perfectly. But when closing it, the Exception was thrown in the second case because the RecyclerView, though not used, existed and when trying to dispose of it, it seems it couldn't. So I just assigned the LayoutManager in both cases although I wasn't using it, and this solved the issue.
Here's the code from my Activity:
ItemsAdapter adapter;
RecyclerView myRecyclerView = findViewById(R.id.my_recycler_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
if (items.size() > 1){
adapter = new ItemsAdapter(this, R.layout.item_layout, items);
myRecyclerView.setLayoutManager(layoutManager);
myRecyclerView.setAdapter(adapter);
} else {
tv_field1.setText(items.get(0).getField1());
tv_field2.setText(items,get(0).getField2());
myRecyclerView.setVisibility(View.GONE);
//This is what I had to add
myRecyclerView.setLayoutManager(layoutManager);
}
Basically, the LayoutManager is being disposed of before your recycler has finished with it.
From the Android source :
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
}
mFirstLayoutComplete = false;
stopScroll();
mIsAttached = false;
if (mLayout != null) {
mLayout.onDetachedFromWindow(this, mRecycler);
}
removeCallbacks(mItemAnimatorRunner);
}
The problem stems from when the stopScroll and it tries to call mLayout.stopSmoothScroller(); without checking if mLayout is null.
I threw togeather a very hacky hot fix for an app I've been working on, but I wouldn't suggest using this for a long term solution as it's very much a bodge. If like me you have a tight deadline it's best to just catch the null pointer exception and ignore it.
My hot fix was just to create a custom View extending the RecyclerView :
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
public class HotFixRecyclerView extends RecyclerView
{
public HotFixRecyclerView( Context context )
{
super( context );
}
public HotFixRecyclerView( Context context, AttributeSet attrs )
{
super( context, attrs );
}
public HotFixRecyclerView( Context context, AttributeSet attrs, int defStyle )
{
super( context, attrs, defStyle );
}
@Override
public void stopScroll()
{
try
{
super.stopScroll();
}
catch( NullPointerException exception )
{
/**
* The mLayout has been disposed of before the
* RecyclerView and this stops the application
* from crashing.
*/
}
}
}
Then change all references from the RecyclerView to HotFixRecyclerView. If you do use it please remove it once Android have patched this issue as it's a bit of a hack.
- If you use recylerview inn XML don't forget to change your XML files accordingly to use
com.your.package.HotFixRecyclerView
instead ofandroid.support.v7.widget.RecyclerView