9

Fatal Exception: java.lang.IndexOutOfBoundsException Inconsistency detected. Invalid item position 5(offset:5).state:24

This kind of crash happens too much!!!

7107 Users & 12k Crashes!!!

I get it in Fabric Crashlytics.

Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 5(offset:5).state:41 at android.support.v7.widget.RecyclerView$Recycler.clear(Unknown Source) at android.support.v7.widget.GapWorker.add(Unknown Source) at android.support.v7.widget.GapWorker.add(Unknown Source) at android.support.v7.widget.GapWorker.remove(Unknown Source) at android.support.v7.widget.GapWorker.add(Unknown Source) at android.support.v7.widget.GapWorker.run(Unknown Source) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5930) at java.lang.reflect.Method.invoke(Method.java) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

DateList is the Fragment which involve RecyclerView:

public class DateList extends Fragment {

DatesItemAdapter adapter;
List<DateItem2> keyList;
CardView cardView;
double v = 1;
float radius = 1;
ProgressBarCircular mCircular;
SwipeRefreshLayout swipeRefreshLayout;
RecyclerView mRecyclerView;
Animation animSlideUp;
Animation animSlideDown;
Uri.Builder builder;
JsonObjectRequest callToServerRequest;

public DateList() {

}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public void onResume() {
    super.onResume();

    swipeRefreshLayout.post(new Runnable() {
                                @Override
                                public void run() {

                                    callToServer(false);

                                }
                            }
    );
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_date_list, container, false);

    ((MainActivity) getActivity()).setTitle(getString(R.string.third_page));
    ((MainActivity) getActivity()).setToolbarVisibility(false);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        container.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
    }

    mCircular = (ProgressBarCircular) view.findViewById(R.id.date_list_progressBar);
    animSlideUp = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_up);
    animSlideDown = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_down);
    swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.date_list_swipe_refresh_layout);
    mRecyclerView = (RecyclerView) view.findViewById(R.id.date_list_container);
    keyList = new ArrayList<>();

    adapter = new DatesItemAdapter(keyList, new DatesItemAdapter.DateItemClickListener() {
        @Override
        public void onClick(View v, int pos) {
            if (pos < keyList.size()) {

                try {
                    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
                    linearLayoutManager.scrollToPositionWithOffset(pos, 0);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }, getActivity(), view);

    ((MainActivity) getActivity()).setTitle("Hello " + getActivity().getResources().getString(R.string.date_list_be) + " " + "World");

    builder = new Uri.Builder();
    builder.scheme("https")
            .authority("mydomain.ir")
            .appendPath("mywebservices")
            .appendPath("myWs");

    cardView = new CardView(getActivity());
    try {
        cardView.setRadius(2);
    } catch (Exception e) {
        e.printStackTrace();
    }

    cardView.findViewById(R.id.date_list_item_card_view);
    radius = cardView.getRadius();

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        try {
            v = ((cardView.getMaxCardElevation()) * 1.5) + ((1 - Math.cos(45)) * (radius));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    try {
        mRecyclerView.addItemDecoration(new DividerItemDecoration(8, getActivity(), v));
    } catch (Exception e) {
        e.printStackTrace();
    }

    try {
        final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(layoutManager);
    } catch (Exception e) {
        e.printStackTrace();
    }

    mRecyclerView.setItemAnimator(new TchAnimator());

    mRecyclerView.setAdapter(adapter);

    swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {

            mRecyclerView.setVisibility(View.GONE);

            callToServer(false);

        }
    });

    final ImageView imageView = (ImageView) view.findViewById(R.id.date_list_header_image);
    final String url = "https://pic.mydomain.ir/pics/" + getResources().getString(R.string.url) + "photo.jpg";
    ImageLoader loader = AppController.getInstance().getImageLoader();
    loader.get(url
            , new ImageLoader.ImageListener() {
                @Override
                public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {
                    try {
                        imageView.setImageBitmap(imageContainer.getBitmap());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onErrorResponse(VolleyError volleyError) {
                }
            });

    return view;
}

public void callToServer(final boolean rTime) {

    String url = builder.toString();

    if (rTime) {
        url = url + "&rTime=1";
    } else {
        url = url + "&rTime=0";
    }

    callToServerRequest = new JsonObjectRequest(Request.Method.GET
            , url
            , null
            , new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

            try {
                JSONArray array = new JSONArray(response.getString("Ticks"));

                // Clears list to replace new list items
                keyList.clear();

                adapter.notifyDataSetChanged();

                for (int i = 0; i < array.length(); i++) {
                    JSONObject obj = new JSONObject(array.get(i).toString());
                    DateItem2 item = new DateItem2();

                    item.setAvailable(obj.getString("available"));
                    item.setType(obj.getString("type"));
                    item.setUrl(obj.getString("url"));
                    item.setTime(obj.getString("time"));
                    item.setDescription(obj.getString("description"));

                    keyList.add(item);
                }

                if (rTime) {
                    mCircular.setVisibility(View.GONE);
                }

                adapter.notifyDataSetChanged();
                mRecyclerView.setVisibility(View.VISIBLE);
                swipeRefreshLayout.setRefreshing(false);

            } catch (JSONException e) {
                e.printStackTrace();
            }

            if (!rTime) {
                callToServer(true);
            }
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {

            if (rTime) {
                mCircular.setVisibility(View.GONE);
            }

            try {
                if (ConnectionDetector.IS_CONNECTED(getActivity())) {
                    if (volleyError.toString().contains("[]") && !rTime) {

                        callToServer(true);

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            swipeRefreshLayout.setRefreshing(false);
        }
    });

    AppController.getInstance().addToRequestQueue(callToServerRequest, "DateList" + "callToServerRequest");
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    try {
        if (getView() != null) {
            getView().setFocusableInTouchMode(true);
            getView().requestFocus();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    getView().setOnKeyListener(new View.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                try {
                    callToServerRequest.cancel();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    });
}
}

callToServer (with false input) Clears the keyList at first and then fills it. after a few milliseconds callToServer (with true input) will be called to clear the keyList again and fill with new items. This two events will repeat in each Refresh.

This is the Adapter:

public class DatesItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private List<DateItem2> items;
private Context mContext;
private DateItemClickListener listener;
private Animation animRotate;
private LogAndReg logAndReg;
private View mainView;

public DatesItemAdapter(List<DateItem2> items, DateItemClickListener listener, Context mContext, View v) {
    this.items = items;
    this.listener = listener;
    this.mContext = mContext;
    animRotate = AnimationUtils.loadAnimation(mContext, R.anim.rotation);
    this.mainView = v;
}

public interface DateItemClickListener {
    void onClick(View v, int pos);
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    try {
        View view = LayoutInflater.from(mContext).inflate(R.layout.date_list_list_item, parent, false);

        switch (viewType) {
            case 0:
                return new GuarantyOpen(view);

            case 1:
                return new GuarantyClose(view);

            case 2:
                return new FreeOpenRefresh(view);

            case 3:
                return new FreeCloseRefresh(view);

            case 4:
                return new FreeOpen(view);

            case 5:
                return new FreeClose(view);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {

    if (holder instanceof GuarantyOpen) {
        final GuarantyOpen h0 = (GuarantyOpen) holder;

        h0.time.setText(items.get(h0.getAdapterPosition()).getTime());
        h0.type.setText(getModelType(h0.getAdapterPosition()));

        if (items.get(h0.getAdapterPosition()).getAvailable().contentEquals("500")) {
            h0.available.setText(R.string.is_available);
        } else {
            h0.available.setText(items.get(h0.getAdapterPosition()).getAvailable());
        }

        if (items.get(h0.getAdapterPosition()).getDescription().contentEquals("")) {
            h0.description.setVisibility(View.GONE);
        } else {
            h0.description.setText(items.get(h0.getAdapterPosition()).getDescription());
        }

        h0.url.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                h0.url.setEnabled(true);

                Intent intent = new Intent(mContext, Reserve.class);
                intent.putExtra("type", items.get(h0.getAdapterPosition()).getType());
                intent.putExtra("time", items.get(h0.getAdapterPosition()).getTime());

                mContext.startActivity(intent);
            }
        });

        h0.url.setBackgroundResource(R.drawable.button_bg_green_selector);

    } else if (holder instanceof GuarantyClose) {
        final GuarantyClose h1 = (GuarantyClose) holder;

        try {
            h1.time.setText(items.get(h1.getAdapterPosition()).getTime());
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (items.get(h1.getAdapterPosition()).getAvailable().contentEquals("500")) {
            h1.available.setText(R.string.is_available);
        } else {
            h1.available.setText(items.get(h1.getAdapterPosition()).getAvailable());
        }

    } else if (holder instanceof FreeOpenRefresh) {
        final FreeOpenRefresh h2 = (FreeOpenRefresh) holder;

        h2.time.setText(items.get(h2.getAdapterPosition()).getTime());
        h2.type.setText(getModelType(h2.getAdapterPosition()));


        if (items.get(h2.getAdapterPosition()).getAvailable().contentEquals("500")) {
            h2.available.setText(R.string.is_available);
        } else {
            h2.available.setText(items.get(h2.getAdapterPosition()).getAvailable());
        }

        if (!((MainActivity) mContext).isLoggedIn()) {
            h2.url.setText(R.string.date_adapter_login);
        } else {
            h2.url.setText(R.string.date_adapter_trans);
        }

        if (items.get(h2.getAdapterPosition()).getDescription().contentEquals("")) {
            h2.description.setVisibility(View.GONE);
        } else {
            h2.description.setText(items.get(h2.getAdapterPosition()).getDescription());
        }

        h2.url.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                h2.url.setEnabled(false);

                if (!((MainActivity) mContext).isLoggedIn()) {
                    h2.url.setEnabled(false);
                    logAndReg = LogAndReg.newInstance();
                    logAndReg.show(((MainActivity) mContext).getSupportFragmentManager(), "tag");
                    h2.childLayout.setVisibility(View.GONE);
                } else {
                    h2.url.setEnabled(true);

                    Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("http://" + items.get(h2.getAdapterPosition()).getUrl()));
                    mContext.startActivity(i);
                }
            }
        });

    } else if (holder instanceof FreeCloseRefresh) {
        final FreeCloseRefresh h3 = (FreeCloseRefresh) holder;

        h3.time.setText(items.get(h3.getAdapterPosition()).getTime());

        if (items.get(h3.getAdapterPosition()).getAvailable().contentEquals("500")) {
            h3.available.setText(R.string.is_available);
        } else {
          h3.available.setText(items.get(h3.getAdapterPosition()).getAvailable());
        }

        if (!((MainActivity) mContext).isLoggedIn()) {
            h3.url.setText(R.string.date_adapter_login);
        } else {
            h3.url.setText(R.string.date_adapter_trans);
        }

    } else if (holder instanceof FreeOpen) {
        final FreeOpen h4 = (FreeOpen) holder;

        h4.time.setText(items.get(h4.getAdapterPosition()).getTime());
        h4.available.setText(items.get(h4.getAdapterPosition()).getAvailable());
        h4.type.setText(getModelType(h4.getAdapterPosition()));

        if (items.get(h4.getAdapterPosition()).getAvailable().contentEquals("500")) {
            h4.available.setText(R.string.is_available);
        } else {
            h4.available.setText(items.get(h4.getAdapterPosition()).getAvailable());
        }

        if (!((MainActivity) mContext).isLoggedIn()) {
            h4.url.setText(R.string.date_adapter_login);
        } else {
            h4.url.setText(R.string.date_adapter_trans);
        }

        if (items.get(h4.getAdapterPosition()).getDescription().contentEquals("")) {
            h4.description.setVisibility(View.GONE);
        } else {
            h4.description.setText(items.get(h4.getAdapterPosition()).getDescription());
        }

        h4.url.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                h4.url.setEnabled(false);

                if (!((MainActivity) mContext).isLoggedIn()) {
                    h4.url.setEnabled(false);
                    logAndReg = LogAndReg.newInstance();
                    logAndReg.show(((MainActivity) mContext).getSupportFragmentManager(), "tag");
                    h4.childLayout.setVisibility(View.GONE);
                } else {
                    h4.url.setEnabled(true);
                    Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("http://" + items.get(h4.getAdapterPosition()).getUrl()));
                    mContext.startActivity(i);
                }
            }
        });

    } else if (holder instanceof FreeClose) {
        final FreeClose h5 = (FreeClose) holder;

        h5.time.setText(items.get(h5.getAdapterPosition()).getTime());

        if (items.get(h5.getAdapterPosition()).getAvailable().contentEquals("500")) {
            h5.available.setText(R.string.is_available);
        } else {
            h5.available.setText(items.get(h5.getAdapterPosition()).getAvailable());
        }

        if (!((MainActivity) mContext).isLoggedIn()) {
            h5.url.setText(R.string.date_adapter_login);
        } else {
            h5.url.setText(R.string.date_adapter_trans);
        }
    }

}

@Override
public int getItemCount() {
    return items.size();
}

@Override
public int getItemViewType(int position) {
    return items.get(position).getexpandState().getValue();
}

private class GuarantyOpen extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView time, available, description, type;
    Button url;
    LinearLayout parentLayout;

    GuarantyOpen(View v) {
        super(v);

        time = (TextView) v.findViewById(R.id.date_list_item_text_time);
        available = (TextView) v.findViewById(R.id.date_list_item_text_available);
        description = (TextView) v.findViewById(R.id.date_list_item_text_type);
        type = (TextView) v.findViewById(R.id.date_list_item_ticket_type);
        url = (Button) v.findViewById(R.id.date_list_item_btn_open_url);

        url.setText(R.string.xml_reserve_reservation_btn);
        parentLayout.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        try {
            listener.onClick(view, getAdapterPosition());
            items.get(getAdapterPosition()).setexpandState(DateItemStatus.GUARANTY_CLOSE);
            onBindViewHolder(this, getAdapterPosition());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private class GuarantyClose extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView time;
    TextView available;
    Button url;
    LinearLayout parentLayout;
    RelativeLayout childLayout;

    GuarantyClose(View v) {
        super(v);

        time = (TextView) v.findViewById(R.id.date_list_item_text_time);
        available = (TextView) v.findViewById(R.id.date_list_item_text_available);
        url = (Button) v.findViewById(R.id.date_list_item_btn_open_url);
        parentLayout = (LinearLayout) v.findViewById(R.id.date_list_item_parent_layout);
        childLayout = (RelativeLayout) v.findViewById(R.id.date_list_item_child_layout);
        childLayout.setVisibility(View.GONE);
        parentLayout.setBackgroundColor(Color.parseColor("#f3faf4"));
        childLayout.setBackgroundColor(Color.parseColor("#c8e6c9"));

        parentLayout.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        try {
            listener.onClick(view, getAdapterPosition());
            items.get(getAdapterPosition()).setexpandState(DateItemStatus.GUARANTY_OPEN);
            onBindViewHolder(this, getAdapterPosition());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private class FreeOpenRefresh extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView time;
    TextView available;
    TextView description;
    TextView type;
    Button url;
    LinearLayout parentLayout;
    RelativeLayout childLayout;

    FreeOpenRefresh(View v) {
        super(v);
        time = (TextView) v.findViewById(R.id.date_list_item_text_time);
        available = (TextView) v.findViewById(R.id.date_list_item_text_available);
        description = (TextView) v.findViewById(R.id.date_list_item_text_type);
        type = (TextView) v.findViewById(R.id.date_list_item_ticket_type);
        url = (Button) v.findViewById(R.id.date_list_item_btn_open_url);

        parentLayout = (LinearLayout) v.findViewById(R.id.date_list_item_parent_layout);
        childLayout = (RelativeLayout) v.findViewById(R.id.date_list_item_child_layout);
        parentLayout.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.date_list_item_btn_refresh) {
            try {
                items.get(getAdapterPosition()).setexpandState(DateItemStatus.FREE_REFRESH_OPEN);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            try {
                listener.onClick(view, getAdapterPosition());
                items.get(getAdapterPosition()).setexpandState(DateItemStatus.FREE_REFRESH_CLOSE);
                onBindViewHolder(this, getAdapterPosition());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

private class FreeCloseRefresh extends RecyclerView.ViewHolder implements View.OnClickListener {
    TextView time;
    TextView available;
    Button url;
    LinearLayout parentLayout;
    RelativeLayout childLayout;

    FreeCloseRefresh(View v) {
        super(v);
        time = (TextView) v.findViewById(R.id.date_list_item_text_time);
        available = (TextView) v.findViewById(R.id.date_list_item_text_available);
        url = (Button) v.findViewById(R.id.date_list_item_btn_open_url);
        parentLayout = (LinearLayout) v.findViewById(R.id.date_list_item_parent_layout);
        childLayout = (RelativeLayout) v.findViewById(R.id.date_list_item_child_layout);

        childLayout.setVisibility(View.GONE);
        parentLayout.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {

        if (view.getId() == R.id.date_list_item_btn_refresh) {
            try {
                items.get(getAdapterPosition()).setexpandState(DateItemStatus.FREE_REFRESH_CLOSE);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            try {
                listener.onClick(view, getAdapterPosition());
                items.get(getAdapterPosition()).setexpandState(DateItemStatus.FREE_REFRESH_OPEN);
                onBindViewHolder(this, getAdapterPosition());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

private class FreeOpen extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView time;
    TextView available;
    TextView description;
    TextView type;
    Button url;
    LinearLayout parentLayout;
    RelativeLayout childLayout;

    FreeOpen(View v) {
        super(v);
        time = (TextView) v.findViewById(R.id.date_list_item_text_time);
        available = (TextView) v.findViewById(R.id.date_list_item_text_available);
        description = (TextView) v.findViewById(R.id.date_list_item_text_type);
        type = (TextView) v.findViewById(R.id.date_list_item_ticket_type);
        url = (Button) v.findViewById(R.id.date_list_item_btn_open_url);
        parentLayout = (LinearLayout) v.findViewById(R.id.date_list_item_parent_layout);
        childLayout = (RelativeLayout) v.findViewById(R.id.date_list_item_child_layout);

        parentLayout.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        try {
            listener.onClick(view, getAdapterPosition());
            items.get(getAdapterPosition()).setexpandState(DateItemStatus.FREE_CLOSER);
            onBindViewHolder(this, getAdapterPosition());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private class FreeClose extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView time;
    TextView available;
    Button url;
    LinearLayout parentLayout;
    RelativeLayout childLayout;

    FreeClose(View v) {
        super(v);
        time = (TextView) v.findViewById(R.id.date_list_item_text_time);
        available = (TextView) v.findViewById(R.id.date_list_item_text_available);
        url = (Button) v.findViewById(R.id.date_list_item_btn_open_url);
        parentLayout = (LinearLayout) v.findViewById(R.id.date_list_item_parent_layout);
        childLayout = (RelativeLayout) v.findViewById(R.id.date_list_item_child_layout);

        childLayout.setVisibility(View.GONE);
        parentLayout.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        try {
            listener.onClick(view, getAdapterPosition());
            items.get(getAdapterPosition()).setexpandState(DateItemStatus.FREE_OPEN);
            onBindViewHolder(this, getAdapterPosition());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private String getModelType(int position) {

    String tType;
    String type = items.get(position).getType();

    switch (type) {
        case "bclass":
            ...
            break;

        case "normal":
            ...
            break;

        case "phone":
            ...
            break;

        case "phone-bclass":
            ...
            break;
    }

    return tType;
}
}

I tried some other solution like THIS and THIS and THIS, but they didn't solve my problem. I think my problem is different with the others because I clear my List in every call.

I couldn't find out what is the problem, at all!!!

Community
  • 1
  • 1
Alireza Noorali
  • 3,129
  • 2
  • 33
  • 80
  • May I ask how you determined which RecyclerView was the source of the problem? I'm in the same boat as you, but I don't know which class to pin the blame on. – Jason Robinson May 09 '17 at 23:44
  • @JasonRobinson : I have the same problem, but I guess this RecyclerView cause the Crash! Because All the users view this Fragment in every use and the other RecyclerViews are in some activities and fragments which are less common. – Alireza Noorali May 11 '17 at 06:44
  • your issue is duplicate. check below issue : https://stackoverflow.com/questions/26827222/inconsistency-detected-in-recyclerview-how-to-change-contents-of-recyclerview-w – dowoo kim Aug 25 '17 at 05:37
  • 1
    @dowookim yes but the previous one was due to bug in RecyclerView it self and the accepted solution is no longer valid. this question really need a different answer now – Ashwini Saini Jan 23 '20 at 14:01
  • Since this question is almost 3 years old, it is even quite unclear which version is being used. The code is messy and it doesn't feature any proper stack-trace; won't touch that. A _minimal_ example app on GitHub might help with reproducing the issue - and getting a reliable answer. – Martin Zeitler Jan 27 '20 at 04:22

4 Answers4

0

This is probably a concurrence problem. I don't know how the JsonObjectRequest works, but its callback is probably being called in a background thread. Therefore, when you scroll while updating your data, the recycler view tries to create views whose information is not present anymore.

In order to avoid that, one possible solution is to wrap the callbacks routine inside a Runnable to be called by a Handler in the main thread. Something like this:

public void callToServer(final boolean rTime) {

    String url = builder.toString();

    if (rTime) {
        url = url + "&rTime=1";
    } else {
        url = url + "&rTime=0";
    }

    final Handler handler = new Handler(getMainLooper());

    callToServerRequest = new JsonObjectRequest(Request.Method.GET
            , url
            , null
            , new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    try {
                        JSONArray array = new JSONArray(response.getString("Ticks"));

                        // Clears list to replace new list items
                        keyList.clear();

                        adapter.notifyDataSetChanged();

                        for (int i = 0; i < array.length(); i++) {
                            JSONObject obj = new JSONObject(array.get(i).toString());
                            DateItem2 item = new DateItem2();

                            item.setAvailable(obj.getString("available"));
                            item.setType(obj.getString("type"));
                            item.setUrl(obj.getString("url"));
                            item.setTime(obj.getString("time"));
                            item.setDescription(obj.getString("description"));

                            keyList.add(item);
                        }

                        if (rTime) {
                            mCircular.setVisibility(View.GONE);
                        }

                        adapter.notifyDataSetChanged();
                        mRecyclerView.setVisibility(View.VISIBLE);
                        swipeRefreshLayout.setRefreshing(false);

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    if (!rTime) {
                        callToServer(true);
                    }
                }
            });

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    if (rTime) {
                        mCircular.setVisibility(View.GONE);
                    }

                    try {
                        if (ConnectionDetector.IS_CONNECTED(getActivity())) {
                            if (volleyError.toString().contains("[]") && !rTime) {

                                callToServer(true);

                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    swipeRefreshLayout.setRefreshing(false);
                }
            });
        }
    });

    AppController.getInstance().addToRequestQueue(callToServerRequest, "DateList" + "callToServerRequest");
}

PS: you don't need to call notifyDataSetChanged after you clear the list. Just after you populate it.

  • Thank's for your answer. I'll try it. but it takes a while to find out if it works. – Alireza Noorali Jan 25 '20 at 05:51
  • @Kevin I still cannot reject or accept this solution because I never face this crash on my own devices. I only get this crash report at Firebase Crashlytics console. So I have to release a new version and look forward to its feedback. – Alireza Noorali Jan 28 '20 at 12:42
  • A good test case is to use an old device with many apps running in background. And, more important, the list must be full of items, the more, the better. Try to scroll the list while updating it. – Carlos Silva Jan 28 '20 at 16:33
  • It didn't work! I'm still getting `java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positiona{2fd6b8b position=9 id=-1, oldPos=-1, pLpos:-1 no parent}` – Alireza Noorali Feb 18 '20 at 08:29
0

Work For Me!

It's a common problems, when you trying to add data in list.

Try to follow below steps :

1 - Clear Your List

2 - Notify Your Adapter

3 - Add Data Into Your List

4 - Notify Adapter

Rohit Soni
  • 1,300
  • 6
  • 12
0

Change your layout manager to WrapContentLinearLayoutManager, this will fix the issue.

public class WrapContentLinearLayoutManager extends LinearLayoutManager {
        public WrapContentLinearLayoutManager(Context context) {
            super(context);
        }

        public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
            super(context, orientation, reverseLayout);
        }

        public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }

        //... constructor
        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            try {
                super.onLayoutChildren(recycler, state);
            } catch (IndexOutOfBoundsException e) {
                LogUtils.debugMsg("probe" + "meet a IOOBE in RecyclerView");
            }
        }

        @Override
        public boolean supportsPredictiveItemAnimations() {
            return false;
        }
    }
kashyap
  • 498
  • 1
  • 6
  • 21
0

I fixed this issue simply by removing support of predictive item animations from LinearLayoutManager:

import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager

class CustomLinearLayoutManager @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : LinearLayoutManager(context, attrs, defStyleAttr, defStyleAttr) {

    override fun supportsPredictiveItemAnimations() = false
}

In case you need horizontal orientation, use

init {
    orientation = HORIZONTAL
}
Micer
  • 8,731
  • 3
  • 79
  • 73
  • I'm not sure about what I'm going to say because you implemented it in Kotlin, but it looks like your code is similar to Kashyap's, but I saw that you commented under his/her post that this solution will reduce the crash to some extent, but it won't go to zero. I have some questions. Can you write it in Java? And the next question is, what is the difference between your code and Kashyap's code? And does your code completely solve the problem? Have you tried this solution in an application that many users use? – Alireza Noorali Apr 04 '20 at 06:06
  • 1
    @AlirezaNoorali The difference is that there's no need to add try-catch in `onLayoutChildren`, because the exception is never thrown (at least in my case). I didn't get any crash since I turned off predictive item animations, but according to https://stackoverflow.com/q/41300626/1101730 there still can be some. I'll push this to thousands of users next week, so let's see. – Micer Apr 06 '20 at 11:00
  • That way we will have a good test. Please share the result of this experiment with us here. – Alireza Noorali Apr 06 '20 at 11:12
  • @AlirezaNoorali looks like this indeed fixed the crash, after a month I can say it's not happening anymore. – Micer May 13 '20 at 14:21
  • If so, that's great – Alireza Noorali May 16 '20 at 12:16