Подтвердить что ты не робот

Recycler View: обнаружена несогласованность. Недействительный адаптер держателя держателя ViewViewer

Ошибка несогласованности просмотра Recycler обнаружена, при прокрутке быстрой или прокрутки при загрузке большего количества элементов.

FATAL EXCEPTION: main
Process: com.pratap.endlessrecyclerview, PID: 21997
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{56a082c position=40 id=-1, oldPos=39, pLpos:39 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4251)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4382)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2864)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1445)
at android.support.v7.widget.RecyclerView.access$400(RecyclerView.java:144)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:282)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

Адаптер

public class DataAdapter extends RecyclerView.Adapter {
    private final int VIEW_ITEM = 1;
    private final int VIEW_PROG = 0;

    private List<Feed> mFeed;
    // The minimum amount of items to have below your current scroll position
    // before loading more.
    private int visibleThreshold = 5;
    private int lastVisibleItem, totalItemCount;
    private boolean loading;
    private OnLoadMoreListener onLoadMoreListener;

    public DataAdapter(List<Feed> feeds, RecyclerView recyclerView) {

        mFeed = feeds;

        if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {

            final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView
                .getLayoutManager();

            recyclerView
                .addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrolled(RecyclerView recyclerView,
                        int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);

                        totalItemCount = linearLayoutManager.getItemCount();
                        lastVisibleItem = linearLayoutManager
                            .findLastVisibleItemPosition();
                        if (!loading
                            && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                            // End has been reached
                            // Do something
                            if (onLoadMoreListener != null) {
                                onLoadMoreListener.onLoadMore();
                            }
                            loading = true;
                        }
                    }
                });
        }
    }

    @Override
    public int getItemViewType(int position) {
        return mFeed.get(position) == null ? VIEW_PROG : VIEW_ITEM;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
        int viewType) {
        RecyclerView.ViewHolder vh;
        if (viewType == VIEW_ITEM) {
            View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.list_row, parent, false);

            vh = new StudentViewHolder(v);
        }
        else {
            View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.progress_item, parent, false);

            vh = new ProgressViewHolder(v);
        }
        return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof StudentViewHolder) {

            Feed singleStudent= (Feed) mFeed.get(position);
            ((StudentViewHolder) holder).tvName.setText(singleStudent.getTitle());
            ((StudentViewHolder) holder).student= singleStudent;
        } else {
            ProgressViewHolder.PROGRESS_BAR.setIndeterminate(true);
        }
    }

    public void setLoaded() {
        loading = false;
    }

    public void  addFeed(Feed feed) {
        mFeed.add(feed);
        //mFeed.addAll(0, (Collection<? extends Feed>) feed);
        notifyItemInserted(mFeed.size());
        //notifyItemRangeInserted(0,mFeed.size());
        notifyDataSetChanged();
        //notifyItemInserted(mFeed.size());
        //setLoaded();
        //notifyItemInserted(mFeed.size());
    }

    public void removeAll(){
        mFeed.clear();
        notifyDataSetChanged();
    }

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

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        this.onLoadMoreListener = onLoadMoreListener;
    }

    public static class StudentViewHolder extends RecyclerView.ViewHolder {
        public TextView tvName;

        public Feed student;
        public StudentViewHolder(View v) {
            super(v);
            tvName = (TextView) v.findViewById(R.id.tvName);

            //tvEmailId = (TextView) v.findViewById(R.id.tvEmailId);
        }
    }

    public static class ProgressViewHolder extends RecyclerView.ViewHolder {
        //public ProgressBar progressBar;
        public static ProgressBar PROGRESS_BAR;
        public ProgressViewHolder(View v) {
            super(v);
            PROGRESS_BAR = (ProgressBar) v.findViewById(R.id.progressBar1);
            //  progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
        }
    }
}

активность

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    private Toolbar toolbar;

    private TextView tvEmptyView;
    private RecyclerView mRecyclerView;
    private DataAdapter mAdapter;
    private LinearLayoutManager mLayoutManager;
    private RestManager mManager;
    private List<Feed> mFeed;
    SwipeRefreshLayout mSwipeRefreshLayout;
    protected Handler handler;
    private int currentPage=1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        tvEmptyView = (TextView) findViewById(R.id.empty_view);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        mSwipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        //studentList = new ArrayList<Student>();
        mFeed = new ArrayList<Feed>();
        handler = new Handler();
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            getSupportActionBar().setTitle("Android Students");

        }
        mManager = new RestManager();

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);

        // use a linear layout manager
        mRecyclerView.setLayoutManager(mLayoutManager);

        // create an Object for Adapter
        mAdapter = new DataAdapter(mFeed,mRecyclerView);

        // set the adapter object to the Recyclerview
        mRecyclerView.setAdapter(mAdapter);
        //   mAdapter.notifyDataSetChanged();

        loadData(false);

        //        if (mFeed.isEmpty()) {
        //            mRecyclerView.setVisibility(View.GONE);
        //            tvEmptyView.setVisibility(View.VISIBLE);
        //
        //        } else {
        //            mRecyclerView.setVisibility(View.VISIBLE);
        //            tvEmptyView.setVisibility(View.GONE);
        //        }

        mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                //add null , so the adapter will check view_type and show progress bar at bottom
                mFeed.add(null);
                mAdapter.notifyItemInserted(mFeed.size() - 1);

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //   remove progress item
                        mFeed.remove(mFeed.size() - 1);
                        // mAdapter.notifyItemRemoved(mFeed.size());
                        //add items one by one
                        int start = mFeed.size();
                        currentPage++;

                        Log.d("CurrentPage", String.valueOf(currentPage));
                        Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1);

                        listCall.enqueue(new Callback<Results>() {

                            @Override
                            public void onResponse(Call<Results> call, Response<Results> response) {
                                mSwipeRefreshLayout.setRefreshing(false);
                                if (response.isSuccess()) {
                                    if (response.body() != null) {
                                        Results feedList = response.body();

                                        // List<Results> newUsers = response.body();

                                        Log.d("Retrofut", String.valueOf(feedList));

                                        for (int i = 0; i < feedList.results.size(); i++) {
                                            Feed feed = feedList.results.get(i);
                                            // mFeed.add(feed);
                                            mAdapter.addFeed(feed);
                                            //                                        mAdapter.notifyDataSetChanged();


                                            //mAdapter.notifyItemInserted(mFeed.size());

                                        }
                                        //    mAdapter.notifyDataSetChanged();
                                    }
                                }
                            }

                            @Override
                            public void onFailure(Call<Results> call, Throwable t) {
                                Log.d("Retrofut", "Error");
                                mFeed.remove(mFeed.size() - 1);
                                mAdapter.notifyItemRemoved(mFeed.size());

                                mAdapter.setLoaded();
                                mSwipeRefreshLayout.setRefreshing(false);
                            }
                        });

                        //        for (int i = 1; i <= 20; i++) {
                        //            studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com"));
                        //
                        //        }

                        mAdapter.setLoaded();
                        //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();

                    }
                }, 2000);
            }
        });
    }

    // load initial data
    private void loadData(final boolean removePreData) {

        Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1);

        listCall.enqueue(new Callback<Results>() {

                             @Override
                             public void onResponse(Call<Results> call, Response<Results> response) {

                                 if (response.isSuccess()) {
                                     if (response.body() != null) {
                                         //  if(removePreData) mAdapter.removeAll();
                                         Results feedList = response.body();
                                         Log.d("Retrofut", String.valueOf(feedList));

                                         for (int i = 0; i < feedList.results.size(); i++) {
                                             Feed feed = feedList.results.get(i);
                                             // mFeed.add(feed);
                                             //mAdapter.notifyDataSetChanged();
                                             mAdapter.addFeed(feed);
                                         }

                                         mSwipeRefreshLayout.setRefreshing(false);
                                     }
                                 }
                             }

                             @Override
                             public void onFailure(Call<Results> call, Throwable t) {
                                 Log.d("Retrofut", String.valueOf(t));
                                 mFeed.remove(mFeed.size() - 1);
                                 mAdapter.notifyItemRemoved(mFeed.size());
                                 mAdapter.setLoaded();
                                 mSwipeRefreshLayout.setRefreshing(false);
                             }
                         }
        );

        //        for (int i = 1; i <= 20; i++) {
        //            studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com"));
        //
        //        }

        mSwipeRefreshLayout.setRefreshing(true);
    }

    @Override
    public void onRefresh() {
        mFeed.clear();
        mAdapter.notifyDataSetChanged();
        loadData(true);
        currentPage=1;
    }
}
4b9b3361

Ответ 1

Он похож на известный андроид ошибка

Существует довольно уродливый, но рабочий подход

public class WrapContentLinearLayoutManager extends LinearLayoutManager {
    //... constructor
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        try {
            super.onLayoutChildren(recycler, state);
        } catch (IndexOutOfBoundsException e) {
            Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens");
        }
    }
}


mRecyclerView.setLayoutManager(new WrapContentGridLayoutManager(getContext(), spanCount));

Для меня это работает без какого-либо побочного эффекта.

Ответ 2

Эта проблема является известной ошибкой RecyclerView. Лучшее решение - очищать список каждый раз перед обновлением RecyclerView.

Для решения этой проблемы просто вызовите notifyDataSetChanged() с пустым списком перед обновлением представления корзины.

Например

//Method for refresh recycle view

if (!yourList.isEmpty())

yourList.clear(); //The list for update recycle view

adapter.notifyDataSetChanged(); 

Ответ 3

Используйте это, чтобы обновить RecyclerView

items.clear(); //here items is an ArrayList populating the RecyclerView
adapter.notifyDataSetChanged();
items.addAll(list);// add new data 
adapter.notifyItemRangeInserted(0, items.size);// notify adapter of new data

`

Ответ 4

У меня была аналогичная проблема, и это решение помогло мне после добавления нового элемента в мое RV:

recyclerView.getRecycledViewPool().clear();
adapter.notifyDataSetChanged();

Ответ 5

У меня возникла эта проблема, прокручивая ее через бесконечный /paging RecyclerView. Корень моей проблемы возник из-за того, что у меня был элемент "header" в начале списка, этот элемент заголовка не был частью источника данных, он был просто вставлен в начало списка adapter. Поэтому при быстрой прокрутке и добавлении новых страниц элементов в RecyclerView adapter и уведомлении adapter о том, что новые данные были вставлены, я не принимал во внимание дополнительный элемент заголовка, тем самым делая размер списка адаптеров неправильно... и вызывает это исключение...

Итак, если вы используете верхний/нижний колонтитул в нашем адаптере RecyclerView, обязательно учтите его при обновлении данных адаптеров.

Пример:

public void addNewPageToList(List<MyData> list)
{   //
    // Make sure you account for any header/footer in your list!
    //
    // Add one to the currentSize to account for the header item.
    //
    int currentSize = this.adapterList.size() + 1;
    this.adapterList.addAll(list);
    notifyItemRangeInserted(currentSize, this.adapterList.size());
}

Edit: Я думаю, вы всегда можете использовать метод адаптера getItemCount(), чтобы получить размер, вместо того, чтобы получать размер из "списка данных" и добавлять к нему. Ваш метод getItemCount() должен уже принимать во внимание любые дополнительные верхние и нижние колонтитулы /etc, которые у вас есть в вашем списке.

Ответ 6

В моем случае я делал это как notifyItemInserted(position); Это вызвало у меня эту проблему, тогда я использовал как и он работал отлично. notifyItemRangeInserted(startIndex,endIndex);

Ответ 7

Может быть, вы можете попробовать это до обновления адаптера:

dataList.clear(); 
patrolListAdapter.notifyDataSetChanged();

Ответ 8

У меня была похожая проблема. Удаление всех видов из RecyclerView помогло мне:

RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
layoutManager.removeAllViews();

Ответ 9

У меня такая же проблема. Воссоздание нового списка таким образом решило проблему совершенно:

в классе адаптера

public void updateItems(List<ComponentEntity> newItems) {
        List<ComponentEntity> updatedItems = new ArrayList<>();
        updatedItems = newItems;
        items = updatedItems;
        notifyDataSetChanged();
}

Ответ 10

Попробуйте изменить private List<Feed> mFeed; в private ArrayList<Feed> mFeed;

И в вашем конструкторе измените mFeed = feeds на

public DataAdapter(List<Feed> feeds, RecyclerView recyclerView) {
    mFeed.addAll(feeds);
    ...

Затем вы можете добавить, как обычно, так:

public void  addFeed(Feed feed) {
    mFeed.add(feed);
    notifyItemInserted(mFeed.size());
}

Поэтому изменение List на ArrayList решило мою проблему. Я думаю, это потому, что List является абстрактным классом, и методы add, remove, clear и т.д. На самом деле там не реализованы. Поэтому, когда вы определяете List (private ArrayList<Feed> mFeed;) и инициируете его с помощью другого List (mFeed = feeds ;), вызов mFeed.add(feed) ничего не делает и заставляет recyclerView генерировать исключение.

Ответ 12

Для меня проблема была в том, что я не публиковал notifyDatasetChanged, когда набор данных изменился, когда я реализовал добавочный поиск.

У меня был список, который был отфильтрован на основе того, что пользователь искал в виджете поиска. Для каждого элемента в списке я делал удаленный запрос, а когда получил результат, я обновлял эту конкретную ячейку.

Я должен был сделать оба уведомления для представления переработчика, чтобы работать

Отфильтруйте исходный набор данных, а затем опубликуйте изменение набора данных.

this.searchResultTable?.post {
    this.searchResultTable?.adapter?.notifyDataSetChanged()
}

После получения ответа снова отправьте уведомления

this.searchResultTable?.post {
    this.searchResultTable?.adapter?.notifyItemChanged(index, updateDataHashMap)
}

Вы должны публиковать обновления, а не отправлять уведомляющие сообщения напрямую, чтобы предотвратить сбой представления рециркулятора при появлении обновления до его представления.

Еще один важный момент: когда вы публикуете отдельные обновления после удаленного ответа, вы должны убедиться, что список, который видит пользователь, является списком, существовавшим на момент отправки запросов.

Ответ 13

Проблема в этой строке кода:

 mFeed = feeds;

Вы назначаете mFeed к экземпляру вызывающего feeds таким образом всякий раз, когда абонент изменяет его переменное (может быть добавлением, очистки или удаления элементов), ваш локальный mFeed изменится

попытаться изменить на

mFeed.addAll(feeds);

не забудьте инициализировать mFeed для любого списка, который соответствует вашим потребностям, например mFeed = new ArrayList<>();