I am trying to use the RecyclerView in my fragments. It shows up fine for the first tab, but when I swipe to the second tab and then back to the first one I get the following er
Reading the bug posted by Isaak, the best solution seems to be assigning the Layout Manager as soon as the view is inflated.
In my case, I only had to assign it on onCreate to fix the problem:
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
In my case i had notifyDataSetChanged()
on the wrong adapter.
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.
com.your.package.HotFixRecyclerView
instead of android.support.v7.widget.RecyclerView
Because it has already inflated pref.xml . You should remove this:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.xxx, container, false);
return mRootView;
}
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);
}