I keep getting java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true when using Fragment with RecyclerView. I have only 1 Activity which switches between multiple fragments. On activity's onCreate I set the default fragment which happens to have a RecyclerView implemented exactly like in documentation. Upon activity startup I get java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true .
The problem is if I load at the beginning an empty fragment container and afterwards navigate to the fragment with RecyclerView, it works fine. Also I don't use android:animateLayoutChanges or notifyDataSetChanged() like stated here Currently I setup the RecyclerView in onResume() method of the Fragment. I've tried switching it to other lifecycle methods but not luck.
Any help is appreciated.
Thanks
I have added only relevant code snippets. I believe that is somehow lifecycle related, giving the fact that it works if I don't set the fragment in onCreate() of the Activity. It worked when I had a ListView instead of RecyclerView. I did not post the code for RecyclerView because it is the same as in documentation.
Activity's onCreate
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG,"### onCreate ###");
super.onCreate(savedInstanceState);
setContentView(R.layout.efficientix_activity_layout);
if(savedInstanceState != null){
checkedSideMenuItemLabel = savedInstanceState.getInt("checkedSideMenuItemLabel");
}
//Init components
initActionBar(checkedSideMenuItemLabel,savedInstanceState);
initSideMenuArrayAdapter();
initSideMenu(checkedSideMenuItemLabel,savedInstanceState);
initActionBarDrawerToggle();
fragmentManager = this.getSupportFragmentManager();
if(savedInstanceState == null){
//Set default fragment upon activity creation.
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DashboardFragment df = new DashboardFragment();
fragmentTransaction.replace(R.id.fragment_container,df,DashboardFragment.class.toString());
fragmentTransaction.commit();
}
}
Fragment's onResume()
public void onResume() {
super.onResume();
if (recylerViewLayoutManager == null) {
recylerViewLayoutManager = new LinearLayoutManager(this.getActivity());
}
recylerView.setLayoutManager(remindersLayoutManager);
initRecylerViewAdapter();
recylerView.setAdapter(recylerViewAdapter);
}
Fragment layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView android:id="@+id/myRecyclerView" style="@style/Main_Content_List_View"/>
</LinearLayout>
Activity's layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:efficientix="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The actionbar toolbar -->
<include layout="@layout/actionbar_toolbar"/>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/menu_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="@+id/fragment_container" android:orientation="vertical">
</LinearLayout>
<include layout="@layout/side_menu_layout"/>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
RecyclerView item layout
<?xml version="1.0" encoding="utf-8"?>
<android.widget.TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Main_Content_Table_Layout_List_Item">
<TableRow style="@style/Main_Content_Table_Row_List_Item">
<TextView android:id="@+id/description"
style="@style/Main_Content_TextView" />
<ImageView android:id="@+id/category"
style="@style/Main_Content_ImageView"/>
</TableRow>
<TableRow style="@style/Main_Content_Table_Row_List_Item">
<TextView android:id="@+id/alert_date"
style="@style/Main_Content_TextView" />
<TextView android:id="@+id/type"
style="@style/Main_Content_TextView" />
</TableRow>
</android.widget.TableLayout>
I saw this happen for me when I used a custom object in the ViewHolder for the Recycler View adapter.
To fix the issue I cleared the custom object which in my case was a timer in the onViewRecycled(ViewHolder holder) for the adapter as below:
This fixed the bug.
Ok so I've found were the problem was. In my ViewHolder I had in addition to the layout Views, an ORMlite entity (could've been any object that was not part of the layout). The problem was that the ViewHolder's equals() and hashcode() methods were based on the entity which was null. The reason it was null was because with RecyclerView you don't have access to the data position in onCreateViewHolder(), but only in onBindViewHolder(). The adapter data is a list of ORMlite entities in my case, and I want to bundle the entity inside the holder. (Still have to find a way to do this...)
I was expecting a NullPointerException in this case. I've manage to get a NullPointerException by calling holder.setIsRecyclable(true).
Hope this helps others in need..
Thanks