Наш QA обнаружил ошибку: при вращении устройства Android (Droid Turbo) произошел следующий сбой, связанный с RecyclerView :
java.lang.IndexOutOfBoundsException: обнаружено несоответствие. Недопустимая позиция элемента 2 (смещение: 2). Состояние: 3
Для меня это выглядит как внутренняя ошибка внутри RecyclerView, так как я не могу думать ни о каком способе того, чтобы это было вызвано непосредственно нашим кодом ...
Кто-нибудь сталкивался с этой проблемой?
Какое будет решение?
Возможно, жестокий обходной путь может заключаться в том, чтобы перехватить исключение, когда оно происходит, и заново создать экземпляр RecyclverView с нуля, чтобы избежать повреждения в поврежденном состоянии.
Но, если возможно, я бы хотел лучше понять проблему (и, возможно, исправить ее в источнике), а не маскировать ее.
Ошибка не легко воспроизвести, но это смертельно, когда это происходит.
Полная трассировка стека:
W/dalvikvm( 7546): threadid=1: thread exiting with uncaught exception (group=0x41987d40)
E/AndroidRuntime( 7546): FATAL EXCEPTION: main
E/AndroidRuntime( 7546): Process: com.oblong.mezzedroid, PID: 7546
E/AndroidRuntime( 7546): java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3
E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3382)
E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340)
E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810)
E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1306)
E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269)
E/AndroidRuntime( 7546): at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523)
E/AndroidRuntime( 7546): at org.liboid.recycler_view.RecyclerViewContainer$LiLinearLayoutManager.onLayoutChildren(RecyclerViewContainer.java:179)
E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1942)
E/AndroidRuntime( 7546): at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
E/AndroidRuntime( 7546): at org.liboid.recycler_view.LiRecyclerView.onLayout(LiRecyclerView.java:30)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
E/AndroidRuntime( 7546): at com.oblong.mezzedroid.workspace.content.bins.BinsContainerLayout.onLayout(BinsContainerLayout.java:22)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
E/AndroidRuntime( 7546): at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
E/AndroidRuntime( 7546): at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
E/AndroidRuntime( 7546): at android.view.View.layout(View.java:14946)
E/AndroidRuntime( 7546): at android.view.ViewGroup.layout(ViewGroup.java:4651)
E/AndroidRuntime( 7546): at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2132)
E/AndroidRuntime( 7546): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1872)
E/AndroidRuntime( 7546): at andro
Ответы:
У меня была (возможно) связанная с этим проблема - ввод нового экземпляра действия с помощью RecyclerView, но с меньшим адаптером вызывал этот сбой для меня.
RecyclerView.dispatchLayout()
Можно попытаться вытащить предметы из металлолома перед звонкомmRecycler.clearOldPositions()
. Следствием этого является то, что он вытягивал элементы из общего пула, позиции которых превышали размер адаптера.К счастью, он делает это только в том случае, если он
PredictiveAnimations
включен, поэтому мое решение состояло в том, чтобы создать подклассGridLayoutManager
(LinearLayoutManager
имеет ту же проблему и «исправить») и переопределить,supportsPredictiveItemAnimations()
чтобы вернуть false:источник
В моем случае (удалить / вставить данные в моей структуре данных) мне нужно было очистить пул утилизации и затем уведомить об изменении набора данных!
mRecyclerView.getRecycledViewPool().clear(); mAdapter.notifyDataSetChanged();
источник
Используйте
notifyDataSetChanged()
вместо этогоnotifyItem...
в этом случае.источник
notifyItem...
и исправили, что начнет работать вместо того, чтобы перерисовывать все элементы.Я решил это, отложив
mRecycler.setAdapter(itemsAdapter)
кассу после добавления всех элементов к адаптеру,mRecycler.addAll(items)
и это сработало. Понятия не имею, почему я сделал это с самого начала, это было из кода библиотеки, который я просмотрел и увидел эти строки в «неправильном порядке», но я почти уверен, что это так, пожалуйста, если кто-то может подтвердить это, объясните, почему это так? Не уверен, если это правильный ответ, дажеисточник
swapAdapter(adapter, true)
вместо,setAdapter(adapter)
и это помогло.У меня была похожая проблема, но не точно такая же. В моем случае в 1 момент я очищал массив, который был передан в просмотрщик
и не вызывая notifyDataSetChanged, поскольку я не хотел, чтобы просмотрщик-очиститель немедленно очищал представления. Я заново заполнял массив mObjects в AsyncTask.
источник
У меня была такая же проблема с recyclerView, поэтому я просто уведомил адаптер об изменении набора данных сразу после очистки списка.
источник
У меня та же проблема. Это происходило, когда я быстро прокручивал и вызывал API и обновлял данные. После попытки сделать все, чтобы предотвратить сбой, я нашел решение.
Это сработает.
источник
Я изменяю данные для
RecyclerView
фонаThread
. Я получил так же,Exception
как ОП. Я добавил это после изменения данных:Надеюсь, поможет
источник
view.recycler_view.post
, я использовалnotifyItemInserted
. В моем случае это был уже поток пользовательского интерфейса.Эта ошибка возникает, когда список в адаптере очищается при прокрутке пользователя, при которой изменяется положение держателя элемента, теряется ссылка между списком и элементом на пользовательском интерфейсе, возникает ошибка в следующем запросе «notifyDataSetChanged» .
Fix:
Просмотрите ваш метод обновления списка. Если вы делаете что-то вроде
Как исправить. Создайте новый объект списка для обработки буфера и после этого снова назначьте основному списку
Спасибо Нхан Цао за эту большую помощь :)
источник
Моя проблема ушла после того, как я изменил свою
Adapter
реализацию, чтобы использовать копию массива элементов вместо ссылки.setItems()
Метод вызывается каждый раз , когда мы имеем новые детали , чтобы показать вRecyclerView
.Вместо того:
Я сделал:
источник
suggestionsRecyclerView.swapAdapter(new CandidatesAdapter(mSuggestions), true);
и это мой конструкторpublic CandidatesAdapter(List<String> suggestionsList) { this.suggestionsList = new ArrayList<>(suggestionsList); }
Я сталкивался с такой же ситуацией. И это было решено добавлением кодов, прежде чем вы очистите свою коллекцию.
mRecyclerView.getRecycledViewPool().clear();
источник
В моем случае я обновлял элементы и вызывал
notifyDataSetChanged
их не в пользовательском интерфейсе. Большую часть времени это работало, но когда много изменений происходило быстро, это приводило к краху. Когда я сделал, вместо этого, в основномзатем он перестал сбой.
источник
Вам нужно только очистить свой список,
OnPostExecute()
а не делатьPull to Refresh
Я обнаружил, что это происходит при прокрутке во время извлечения для обновления , так как я очищал список до
async task
, в результате чегоjava.lang.IndexOutOfBoundsException: Inconsistency detected.
Таким образом, вы не закончите с непоследовательностью
источник
Это также может быть связано с настройкой адаптера несколько раз одновременно. У меня был метод обратного вызова, который запускался 5-6 раз в одно и то же время, и я устанавливал адаптер в этом обратном вызове, чтобы RecycledViewPool не мог обрабатывать все эти данные одновременно. Это большой шанс, но лучше все равно проверить.
источник
использование
вместо
в таком случае.
источник
Для решения этой проблемы просто вызовите notifyDataSetChanged () с пустым списком перед обновлением представления корзины.
Например
hcpArray.clear (); // Список для вида обновления корзины
источник
В моем случае я просто удалил строку с
setHasStableIds(true);
источник
В моем случае я пытался изменить содержимое моего адаптера в фоновом потоке, но вызвал notify * в основном / пользовательском потоке.
Это невозможно! Причина, по которой уведомление принудительно направляется в основной поток, заключается в том, что администратор повторного просмотра требует, чтобы вы отредактировали вспомогательный адаптер в основном потоке, даже в одном стеке вызовов.
Чтобы решить эту проблему, убедитесь, что каждая операция с вашим адаптером, а также каждый вызов notify ... выполняется в потоке пользовательского интерфейса / main !
источник
Недавно я столкнулся с этой неприятной трассировкой стека с новыми компонентами архитектуры Android. По сути, у меня есть список элементов в моей ViewModel, которые наблюдаются моим фрагментом с использованием LiveData. Когда ViewModel публикует новое значение для данных, фрагмент обновляет адаптер, передавая эти новые элементы данных и уведомляя адаптер об изменениях.
К сожалению, при передаче новых элементов данных в адаптер я не смог учесть тот факт, что и ViewModel, и Adapter будут указывать на одну и ту же ссылку на объект! Это означает, что если я обновлю данные и вызову
postValue()
из ViewModel, появится очень маленькое окно, где данные могут быть обновлены, а адаптер еще не уведомлен!Мое исправление состояло в том, чтобы создать новую копию элементов при передаче в адаптер:
mList = new ArrayList<>(passedList);
С этим очень простым исправлением вы можете быть уверены, что данные вашего адаптера не изменятся до тех пор, пока ваш адаптер не будет уведомлен.
источник
Это единственное решение, которое сработало для меня, даже пробуя многие решения сверху.
1.) Использование
2.) Напишите этот метод в адаптере
stockListModels -> этот список, который вы используете в адаптере.
источник
Для меня это сработало после добавления этой строки кода:
источник
эта проблема может возникнуть, когда вы пытаетесь очистить свой список, если вы собираетесь очистить свой список данных, особенно когда вы используете команду pull для обновления, попробуйте использовать логический флаг, инициализируйте его как false и внутри метода OnRefresh сделайте его истинным, очистите свой dataList Если флаг равен true, то перед тем, как добавить к нему новые данные и после этого сделать его ложным.
ваш код может быть таким
источник
У меня была такая же проблема ранее. Наконец-то нашел обходной путь для этого
Что я делаю, это уведомляю адаптер, что элемент удален, а затем уведомляю об изменении диапазона набора данных адаптера
источник
Я столкнулся с подобной проблемой и просто понял это. Я жестко запрограммировал несколько примеров для тестового примера, но не гарантировал, что каждый из них вернул уникальный идентификатор, и это вызвало для меня приведенный ниже сбой. Исправление идентификаторов решило проблему, надеюсь, это поможет кому-то еще!
источник
я тоже однажды получил ошибку:
Причина: я пытался обновить представление Recycler из асинхронной задачи, одновременно пытаясь получить старые удаленные viewHolders;
Код: я генерирую данные при нажатии кнопки, логика выглядит следующим образом
Проблема: всякий раз, когда я быстро прокручиваю, прежде чем генерировать свои данные, я получаю
Решение: вместо очистки RecyclerView перед генерацией моих данных я оставляю их, а затем заменяю их новыми данными, вызовом NotifyDatasetChanged, как показано ниже;
источник
Просто удалите все виды вашего менеджера макета, прежде чем уведомить. лайк:
источник
Использование
ListAdapter (androidx.recyclerview.widget.ListAdapter)
вызоваadapter.submitList(null)
перед звонкомadapter.submitList(list)
:источник
Это исключение возникло по API 19, 21 (но не по новому). В сопрограмме Kotlin я загрузил данные (в фоновом потоке) и добавил в поток пользовательского интерфейса и показал их:
адаптер:
По некоторым причинам Android не рендерится достаточно быстро или что-то еще, поэтому я обновляю список в
post
методеRecyclerView
(добавить, удалить, обновить события элементов):Это исключение похоже на «Невозможно вызвать этот метод в обратном вызове прокрутки. Обратные вызовы прокрутки могут выполняться во время этапа измерения и разметки, когда вы не можете изменить данные RecyclerView. Любой вызов метода, который может изменить структуру RecyclerView или содержимое адаптера, следует отложить до следующий кадр. ": Recyclerview - не может вызвать этот метод в обратном вызове прокрутки .
источник
Я обнаружил, что настройка mRecycler.setLayoutFrozen (true); в методе onRefresh объекта swipeContainer.
решил проблему для меня.
источник
Это довольно неприятная ошибка.
Для обработки моего клика по элементу я использовал реализацию,
RecyclerView.OnItemTouchListener
аналогичную решению, найденному в этом вопросе .После многократного обновления
RecyclerView
источника данных и щелчка по элементуIndexOutOfBoundsException
мое приложение вылетало. Когда по элементу щелкают,RecyclerView
внутренняя часть ищет правильный базовый вид и возвращает его положение. Проверяя исходный код, я увидел, что они естьTasks
иThreads
запланированы. Короче говоря, по сути, это просто какое-то незаконное состояние, когда два источника данных смешаны, а не синхронизированы, и все это становится диким.Исходя из этого, я снял с реализации из
RecyclerView.OnItemTouchListener
и просто поймал нажмите наViewHolder
оAdapter
себе:Возможно, это не лучшее решение, но пока без сбоев. Надеюсь, это сэкономит вам время :).
источник