Home » Android » android recyclerview inconsistency detected invalid recycler viewholder position

android recyclerview inconsistency detected invalid recycler viewholder position

Posted by: admin May 14, 2020 Leave a comment

Questions:

I have recycler view in my app. The UI is similar to Google Play Store app. It has two view pagers and the list and grid of items in alternate manner. All data is fetched from the web services and is bifurcated in two API calls. The data for list and grid is populated from another API. The problem is I am getting this crash when I scroll the recyclerview very fast. On scrolling the recyclerview, API call for loading the data in list/grid is from bindData().
Read numerous questions on this topic but couldn’t reached upto solution.

Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{396df09 position=3 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent}
       at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4505)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4636)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4617)
       at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)
       at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1390)
       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:574)
       at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:2979)
       at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:2619)
       at android.view.View.measure(View.java:18811)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
       at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
       at android.support.v7.widget.CardView.onMeasure(CardView.java:208)
       at android.view.View.measure(View.java:18811)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
       at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
       at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
       at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
       at android.view.View.measure(View.java:18811)
       at android.support.v7.widget.RecyclerView$LayoutManager.measureChildWithMargins(RecyclerView.java:7487)
       at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1416)
       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:574)
       at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3028)
       at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2906)
       at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3283)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:122)
       at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
       at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1192)
       at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:814)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1187)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
       at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
       at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2680)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2198)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1958)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1134)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6045)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:860)
       at android.view.Choreographer.doCallbacks(Choreographer.java:672)
       at android.view.Choreographer.doFrame(Choreographer.java:608)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
       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:5441)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

This is my main recyclerview adapter:

public class HomeScreenDataAdapterv2 extends RecyclerView.Adapter<HomeScreenViewHolder> {
private HomeScreenActionHandler homeScreenActionHandler;
private ArrayList<HomeScreenParentDataModel> homeScreenParentDataModels;
public HomeScreenDataAdapterv2(ArrayList<HomeScreenParentDataModel> homeScreenParentDataModels) {
this.homeScreenParentDataModels = homeScreenParentDataModels;
}
@Override
public HomeScreenViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View holderView;
Context ctx = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(ctx);
switch (viewType) {
case HomeScreenDataViewTypes.HOME_SCREEN_MAIN_BANNER_VIEW_TYPE:
holderView = inflater.inflate(R.layout.home_main_banner_adapter, parent, false);
return new HomeScreenMainBannerViewHolder(ctx, holderView, homeScreenActionHandler);
case HomeScreenDataViewTypes.HOME_SCREEN_HOT_DEALS_VIEW_TYPE:
holderView = inflater.inflate(R.layout.home_hot_deals_adapter, parent, false);
return new HotDealsViewHolder(ctx, holderView, homeScreenActionHandler);
case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCKS_LIST_VIEW_TYPE:
holderView = inflater.inflate(R.layout.home_screen_dynamic_blocks_parent_list_adapter, parent, false);
return new HomeScreenDynamicBlocksListViewHolder(ctx, holderView, homeScreenActionHandler);
case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCK_GRID_VIEW_TYPE:
holderView = inflater.inflate(R.layout.home_screen_dynamic_blocks_parent_grid_adapter, parent, false);
return new HomeScreenDynamicBlocksGridViewHolder(ctx, holderView, homeScreenActionHandler);
default:
return null;
}
}
@Override
public void onBindViewHolder(HomeScreenViewHolder holder, int position) {
HomeScreenParentDataModel homeScreenParentDataModel = homeScreenParentDataModels.get(position);
switch (homeScreenParentDataModels.get(position).getHome_screen_view_type()) {
case HomeScreenDataViewTypes.HOME_SCREEN_MAIN_BANNER_VIEW_TYPE:
((HomeScreenMainBannerViewHolder) holder).bindData((HomeBannerDataModel) homeScreenParentDataModel);
break;
case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCKS_LIST_VIEW_TYPE:
((HomeScreenDynamicBlocksListViewHolder) holder).bindListData((HomeScreenDynamicBlocksDataModel) homeScreenParentDataModel);
break;
case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCK_GRID_VIEW_TYPE:
((HomeScreenDynamicBlocksGridViewHolder) holder).bindGridData((HomeScreenDynamicBlocksDataModel) homeScreenParentDataModel);
break;
}
}
@Override
public int getItemCount() {
return homeScreenParentDataModels.size();
}
@Override
public int getItemViewType(int position) {
return homeScreenParentDataModels.get(position).getHome_screen_view_type();
}
private static class HomeScreenMainBannerViewHolder extends HomeScreenViewHolder {
private Context ctx;
private HomeScreenActionHandler homeScreenActionHandler;
private ViewPager main_banner_view_pager;
private CirclePageIndicator pager_indicator;
HomeScreenMainBannerViewHolder(Context ctx, View itemView, HomeScreenActionHandler homeScreenActionHandler) {
super(itemView);
this.ctx = ctx;
this.homeScreenActionHandler = homeScreenActionHandler;
main_banner_view_pager = (ViewPager) itemView.findViewById(R.id.main_banner_view_pager);
main_banner_view_pager.setClipToPadding(false);
int padding = Util.convertDptoPixel(ctx, 9.0f);
main_banner_view_pager.setPageMargin(
Util.convertDptoPixel(ctx, 9.0f));
main_banner_view_pager.setPadding(padding, 0, padding, 0);
pager_indicator = (CirclePageIndicator) itemView.findViewById(R.id.pager_indicator);
}
public void bindData(HomeBannerDataModel homeMainBannerDataModel) {
HomeMainBannerPagerAdapter mainBannerAdapter = new HomeMainBannerPagerAdapter(ctx, homeMainBannerDataModel.getBannerList());
mainBannerAdapter.setHomeScreenActionHandler(homeScreenActionHandler);
main_banner_view_pager.setAdapter(mainBannerAdapter);
pager_indicator.setViewPager(main_banner_view_pager);
}
}
private static class HomeScreenDynamicBlocksListViewHolder extends HomeScreenViewHolder implements View.OnClickListener {
private HomeScreenActionHandler homeScreenActionHandler;
private RubikMediumTextView section_name;
private RubikMediumButton btn_view_all;
private RecyclerView dynamic_widgets_container;
private Widget widget;
private HomeScreenBlockListAdapter blockListAdapter;
HomeScreenDynamicBlocksListViewHolder(Context ctx, View itemView, HomeScreenActionHandler homeScreenActionHandler) {
super(itemView);
this.homeScreenActionHandler = homeScreenActionHandler;
section_name = (RubikMediumTextView) itemView.findViewById(R.id.section_name);
btn_view_all = (RubikMediumButton) itemView.findViewById(R.id.btn_view_all);
btn_view_all.setOnClickListener(this);
dynamic_widgets_container = (RecyclerView) itemView.findViewById(R.id.dynamic_widgets_container);
section_name.setTextColor(Color.parseColor("#546682"));
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
linearLayoutManager.setAutoMeasureEnabled(true);
dynamic_widgets_container.setLayoutManager(linearLayoutManager);
dynamic_widgets_container.addItemDecoration(new DividerItemDecoration(ctx));
dynamic_widgets_container.setNestedScrollingEnabled(false);
}
void bindListData(HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel) {
widget = dynamicBlocksDataModel.getWidget();
if (widget != null) {
section_name.setText(widget.getName());
ArrayList<BuyListingsModel> dynamicModels = widget.getDynamicDataModels();
if (blockListAdapter == null) {
blockListAdapter = new HomeScreenBlockListAdapter(dynamicModels, homeScreenActionHandler);
dynamic_widgets_container.setAdapter(blockListAdapter);
}
if (dynamicModels.isEmpty()) {
homeScreenActionHandler.fetchWidgetData(widget.getName(), getAdapterPosition(), dynamicBlocksDataModel, blockListAdapter);
}
}
}
@Override
public void onClick(View v) {
if (homeScreenActionHandler != null && widget != null) {
homeScreenActionHandler.gotoSearchResult(widget.getListingFilters());
}
}
}
private static class HomeScreenDynamicBlocksGridViewHolder extends HomeScreenViewHolder implements View.OnClickListener {
private HomeScreenActionHandler homeScreenActionHandler;
private RubikMediumTextView section_name;
private RubikMediumButton btn_view_all;
private RecyclerView dynamic_widgets_container;
private Widget widget;
private HomeScreenBlockGridAdapter blockGridAdapter;
HomeScreenDynamicBlocksGridViewHolder(Context ctx, View itemView, HomeScreenActionHandler homeScreenActionHandler) {
super(itemView);
this.homeScreenActionHandler = homeScreenActionHandler;
section_name = (RubikMediumTextView) itemView.findViewById(R.id.section_name);
btn_view_all = (RubikMediumButton) itemView.findViewById(R.id.btn_view_all);
btn_view_all.setOnClickListener(this);
dynamic_widgets_container = (RecyclerView) itemView.findViewById(R.id.dynamic_widgets_container);
GridLayoutManager gridLayoutManager = new GridLayoutManager(ctx, 2);
gridLayoutManager.setAutoMeasureEnabled(true);
dynamic_widgets_container.addItemDecoration(new GridSpacingItemDecoration(2, 1, true));
dynamic_widgets_container.setNestedScrollingEnabled(false);
dynamic_widgets_container.setLayoutManager(gridLayoutManager);
}
void bindGridData(HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel) {
widget = dynamicBlocksDataModel.getWidget();
if (widget != null) {
section_name.setText(widget.getName());
ArrayList<BuyListingsModel> dynamicModels = widget.getDynamicDataModels();
if (blockGridAdapter == null) {
blockGridAdapter = new HomeScreenBlockGridAdapter(dynamicModels, homeScreenActionHandler);
dynamic_widgets_container.setAdapter(blockGridAdapter);
}
if (dynamicModels.isEmpty()) {
homeScreenActionHandler.fetchWidgetData(widget.getName(), getAdapterPosition(), dynamicBlocksDataModel, blockGridAdapter);
}
}
}
@Override
public void onClick(View v) {
if (homeScreenActionHandler != null && widget != null) {
homeScreenActionHandler.gotoSearchResult(widget.getListingFilters());
}
}
}
public interface HomeScreenActionHandler {
void gotoCategoryListing(String categoryName);
void gotoCategoryPage();
void handleBannerClick(Banner banner);
void gotoSearchResult(Bundle listingFiltersBundle);
void fetchWidgetData(String widgetName, int adapterPosition, HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel, RecyclerView.Adapter listAdapter);
void performWishlistAction(BuyListingsModel buyListingsModel, int childApdaterPosition, RecyclerView.Adapter listAdapter);
void performBlockClick(String listing_id, boolean isInWatchlist);
}
public void setHomeScreenActionHandler(HomeScreenActionHandler homeScreenActionHandler) {
this.homeScreenActionHandler = homeScreenActionHandler;
}
}

This is API call for loading data in list:

public void fetchWidgetData(final String widgetName, final int adapterPosition,
final HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel, final RecyclerView.Adapter listAdapter) {
final Widget widget = dynamicBlocksDataModel.getWidget();
Bundle b = widget.getListingFilters();
HashMap<String, String> params = new HashMap<>();
if (!b.containsKey("recently_sold"))
params.put("isSearch", "1");
Set<String> keySet = b.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext()) {
String key = it.next();
params.put(key, b.getString(key));
}
Response.Listener<JSONObject> responseListener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
String code = response.getString("code");
if (code.equalsIgnoreCase("success")) {
JSONArray dataArray = response.getJSONArray("data");
ArrayList<BuyListingsModel> models = HomeScreenDataParser
.getDynamicBlocksModelList(dataArray);
if (models != null && !models.isEmpty()) {
ArrayList<BuyListingsModel> buyListingsModels = widget.getDynamicDataModels();
buyListingsModels.clear();
if (listAdapter != null) {
int size = models.size();
int upperbound = listAdapter instanceof HomeScreenBlockListAdapter ? 3 : 4;
for (int i = 0; i < size && i < upperbound; i++) {
buyListingsModels.add(models.get(i));
}
listAdapter.notifyItemRangeInserted(0, buyListingsModels.size());
}
//homeScreenDataAdapterv2.notifyItemChanged(adapterPosition);
}
} else if (code.equalsIgnoreCase("failed")) {
handleError(response);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
};
Api.getHomeScreenWidgetDetails(widgetName, responseListener, errorListener, ctx, params);
How to&Answers:

Since you’re actually replacing all data, calling notifyItemRangeInserted() without actually inserting anything into the adapter raises this issue. You have to call the correct notifier just after setting the actual data to the adapter or to be more precise underlying list the list.

notifyItemRangeInserted(pos, count) notifies the adapter to expect count items inserted at pos. Therefore the size of the list should have grown by count, not just be count. Since you replace all data, you should call notifyDataSetChanged() instead or use DiffUtil to calculate the actual diff of your data. But then you don’t have to worry about which notification to use anymore.

listAdapter.notifyDataSetChanged(); 

Answer:

I had the same issue and i searched all over the internet and tried alot of the solutions. Finally my issue was fixed by setting ItemAnimator to null for RecyclerView.

recyclerView.setItemAnimator(null); 

This will fix the issue

Answer:

In onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) check,

if(position != RecyclerView.NO_POSITION){ // Do your binding here } 

This worked for me.