У меня есть вид переработчика, который отлично работает на всех устройствах, кроме Samsung. На самсунг я получаю
java.lang.IndexOutOfBoundsException: обнаружено несоответствие. Неправильный вид держателя адаптера positionViewHolder
когда я вернусь к фрагменту с видом переработчика из другого действия.
Код адаптера:
public class FeedRecyclerAdapter extends RecyclerView.Adapter<FeedRecyclerAdapter.MovieViewHolder> {
public static final String getUserPhoto = APIConstants.BASE_URL + APIConstants.PICTURE_PATH_SMALL;
Movie[] mMovies = null;
Context mContext = null;
Activity mActivity = null;
LinearLayoutManager mManager = null;
private Bus uiBus = null;
int mCountOfLikes = 0;
//Constructor
public FeedRecyclerAdapter(Movie[] movies, Context context, Activity activity,
LinearLayoutManager manager) {
mContext = context;
mActivity = activity;
mMovies = movies;
mManager = manager;
uiBus = BusProvider.getUIBusInstance();
}
public void setMoviesAndNotify(Movie[] movies, boolean movieIgnored) {
mMovies = movies;
int firstItem = mManager.findFirstVisibleItemPosition();
View firstItemView = mManager.findViewByPosition(firstItem);
int topOffset = firstItemView.getTop();
notifyDataSetChanged();
if(movieIgnored) {
mManager.scrollToPositionWithOffset(firstItem - 1, topOffset);
} else {
mManager.scrollToPositionWithOffset(firstItem, topOffset);
}
}
// Create new views (called by layout manager)
@Override
public MovieViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.feed_one_recommended_movie_layout, parent, false);
return new MovieViewHolder(view);
}
// Replaced contend of each view (called by layout manager)
@Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
setLikes(holder, position);
setAddToCollection(holder, position);
setTitle(holder, position);
setIgnoreMovieInfo(holder, position);
setMovieInfo(holder, position);
setPosterAndTrailer(holder, position);
setDescription(holder, position);
setTags(holder, position);
}
// returns item count (called by layout manager)
@Override
public int getItemCount() {
return mMovies != null ? mMovies.length : 0;
}
private void setLikes(final MovieViewHolder holder, final int position) {
List<Reason> likes = new ArrayList<>();
for(Reason reason : mMovies[position].reasons) {
if(reason.title.equals("Liked this movie")) {
likes.add(reason);
}
}
mCountOfLikes = likes.size();
holder.likeButton.setText(mContext.getString(R.string.like)
+ Html.fromHtml(getCountOfLikesString(mCountOfLikes)));
final MovieRepo repo = MovieRepo.getInstance();
final int pos = position;
final MovieViewHolder viewHolder = holder;
holder.likeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mMovies[pos].isLiked) {
repo.unlikeMovie(AuthStore.getInstance()
.getAuthToken(), mMovies[pos].id, new Callback<Movie>() {
@Override
public void success(Movie movie, Response response) {
Drawable img = mContext.getResources().getDrawable(R.drawable.ic_like);
viewHolder.likeButton
.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null);
if (--mCountOfLikes <= 0) {
viewHolder.likeButton.setText(mContext.getString(R.string.like));
} else {
viewHolder.likeButton
.setText(Html.fromHtml(mContext.getString(R.string.like)
+ getCountOfLikesString(mCountOfLikes)));
}
mMovies[pos].isLiked = false;
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(mContext.getApplicationContext(),
mContext.getString(R.string.cannot_like), Toast.LENGTH_LONG)
.show();
}
});
} else {
repo.likeMovie(AuthStore.getInstance()
.getAuthToken(), mMovies[pos].id, new Callback<Movie>() {
@Override
public void success(Movie movie, Response response) {
Drawable img = mContext.getResources().getDrawable(R.drawable.ic_liked_green);
viewHolder.likeButton
.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null);
viewHolder.likeButton
.setText(Html.fromHtml(mContext.getString(R.string.like)
+ getCountOfLikesString(++mCountOfLikes)));
mMovies[pos].isLiked = true;
setComments(holder, position);
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(mContext,
mContext.getString(R.string.cannot_like), Toast.LENGTH_LONG).show();
}
});
}
}
});
}
private void setComments(final MovieViewHolder holder, final int position) {
holder.likeAndSaveButtonLayout.setVisibility(View.GONE);
holder.commentsLayout.setVisibility(View.VISIBLE);
holder.sendCommentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.commentsInputEdit.getText().length() > 0) {
CommentRepo repo = CommentRepo.getInstance();
repo.sendUserComment(AuthStore.getInstance().getAuthToken(), mMovies[position].id,
holder.commentsInputEdit.getText().toString(), new Callback<Void>() {
@Override
public void success(Void aVoid, Response response) {
Toast.makeText(mContext, mContext.getString(R.string.thanks_for_your_comment),
Toast.LENGTH_SHORT).show();
hideCommentsLayout(holder);
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(mContext, mContext.getString(R.string.cannot_add_comment),
Toast.LENGTH_LONG).show();
}
});
} else {
hideCommentsLayout(holder);
}
}
});
}
private void hideCommentsLayout(MovieViewHolder holder) {
holder.commentsLayout.setVisibility(View.GONE);
holder.likeAndSaveButtonLayout.setVisibility(View.VISIBLE);
}
private void setAddToCollection(final MovieViewHolder holder, int position) {
final int pos = position;
if(mMovies[position].isInWatchlist) {
holder.saveButton
.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_check_green, 0, 0, 0);
}
final CollectionRepo repo = CollectionRepo.getInstance();
holder.saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!mMovies[pos].isInWatchlist) {
repo.addMovieToCollection(AuthStore.getInstance().getAuthToken(), 0, mMovies[pos].id, new Callback<MovieCollection[]>() {
@Override
public void success(MovieCollection[] movieCollections, Response response) {
holder.saveButton
.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_check_green, 0, 0, 0);
mMovies[pos].isInWatchlist = true;
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(mContext, mContext.getString(R.string.movie_not_added_to_collection),
Toast.LENGTH_LONG).show();
}
});
} else {
repo.removeMovieFromCollection(AuthStore.getInstance().getAuthToken(), 0,
mMovies[pos].id, new Callback<MovieCollection[]>() {
@Override
public void success(MovieCollection[] movieCollections, Response response) {
holder.saveButton
.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_plus, 0, 0, 0);
mMovies[pos].isInWatchlist = false;
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(mContext,
mContext.getString(R.string.cannot_delete_movie_from_watchlist),
Toast.LENGTH_LONG).show();
}
});
}
}
});
}
private String getCountOfLikesString(int countOfLikes) {
String countOfLikesStr;
if(countOfLikes == 0) {
countOfLikesStr = "";
} else if(countOfLikes > 999) {
countOfLikesStr = " " + (countOfLikes/1000) + "K";
} else if (countOfLikes > 999999){
countOfLikesStr = " " + (countOfLikes/1000000) + "M";
} else {
countOfLikesStr = " " + String.valueOf(countOfLikes);
}
return "<small>" + countOfLikesStr + "</small>";
}
private void setTitle(MovieViewHolder holder, final int position) {
holder.movieTitleTextView.setText(mMovies[position].title);
holder.movieTitleTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MovieDetailActivity.openView(mContext, mMovies[position].id, true, false);
}
});
}
private void setIgnoreMovieInfo(MovieViewHolder holder, final int position) {
holder.ignoreMovie.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MovieRepo repo = MovieRepo.getInstance();
repo.hideMovie(AuthStore.getInstance().getAuthToken(), mMovies[position].id,
new Callback<Void>() {
@Override
public void success(Void aVoid, Response response) {
Movie[] newMovies = new Movie[mMovies.length - 1];
for (int i = 0, j = 0; j < mMovies.length; i++, j++) {
if (i != position) {
newMovies[i] = mMovies[j];
} else {
if (++j < mMovies.length) {
newMovies[i] = mMovies[j];
}
}
}
uiBus.post(new MoviesChangedEvent(newMovies));
setMoviesAndNotify(newMovies, true);
Toast.makeText(mContext, mContext.getString(R.string.movie_ignored),
Toast.LENGTH_SHORT).show();
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(mContext, mContext.getString(R.string.movie_ignored_failed),
Toast.LENGTH_LONG).show();
}
});
}
});
}
private void setMovieInfo(MovieViewHolder holder, int position) {
String imdp = "IMDB: ";
String sources = "", date;
if(mMovies[position].showtimes != null && mMovies[position].showtimes.length > 0) {
int countOfSources = mMovies[position].showtimes.length;
for(int i = 0; i < countOfSources; i++) {
sources += mMovies[position].showtimes[i].name + ", ";
}
sources = sources.trim();
if(sources.charAt(sources.length() - 1) == ',') {
if(sources.length() > 1) {
sources = sources.substring(0, sources.length() - 2);
} else {
sources = "";
}
}
} else {
sources = "";
}
imdp += mMovies[position].imdbRating + " | ";
if(sources.isEmpty()) {
date = mMovies[position].releaseYear;
} else {
date = mMovies[position].releaseYear + " | ";
}
holder.movieInfoTextView.setText(imdp + date + sources);
}
private void setPosterAndTrailer(final MovieViewHolder holder, final int position) {
if (mMovies[position] != null && mMovies[position].posterPath != null
&& !mMovies[position].posterPath.isEmpty()) {
Picasso.with(mContext)
.load(mMovies[position].posterPath)
.error(mContext.getResources().getDrawable(R.drawable.noposter))
.into(holder.posterImageView);
} else {
holder.posterImageView.setImageResource(R.drawable.noposter);
}
holder.posterImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MovieDetailActivity.openView(mActivity, mMovies[position].id, false, false);
}
});
if(mMovies[position] != null && mMovies[position].trailerLink != null
&& !mMovies[position].trailerLink.isEmpty()) {
holder.playTrailer.setVisibility(View.VISIBLE);
holder.playTrailer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MovieDetailActivity.openView(mActivity, mMovies[position].id, false, true);
}
});
}
}
private void setDescription(MovieViewHolder holder, int position) {
String text = mMovies[position].overview;
if(text == null || text.isEmpty()) {
holder.descriptionText.setText(mContext.getString(R.string.no_description));
} else if(text.length() > 200) {
text = text.substring(0, 196) + "...";
holder.descriptionText.setText(text);
} else {
holder.descriptionText.setText(text);
}
final int pos = position;
holder.descriptionText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MovieDetailActivity.openView(mActivity, mMovies[pos].id, false, false);
}
});
}
private void setTags(MovieViewHolder holder, int position) {
List<String> tags = Arrays.asList(mMovies[position].tags);
if(tags.size() > 0) {
CastAndTagsFeedAdapter adapter = new CastAndTagsFeedAdapter(tags,
mContext, ((FragmentActivity) mActivity).getSupportFragmentManager());
holder.tags.setItemMargin(10);
holder.tags.setAdapter(adapter);
} else {
holder.tags.setVisibility(View.GONE);
}
}
// class view holder that provide us a link for each element of list
public static class MovieViewHolder extends RecyclerView.ViewHolder {
TextView movieTitleTextView, movieInfoTextView, descriptionText, reasonsCountText;
TextView reasonText1, reasonAuthor1, reasonText2, reasonAuthor2;
EditText commentsInputEdit;
Button likeButton, saveButton, playTrailer, sendCommentButton;
ImageButton ignoreMovie;
ImageView posterImageView, userPicture1, userPicture2;
TwoWayView tags;
RelativeLayout mainReasonsLayout, firstReasonLayout, secondReasonLayout, reasonsListLayout;
RelativeLayout commentsLayout;
LinearLayout likeAndSaveButtonLayout;
ProgressBar progressBar;
public MovieViewHolder(View view) {
super(view);
movieTitleTextView = (TextView)view.findViewById(R.id.movie_title_text);
movieInfoTextView = (TextView)view.findViewById(R.id.movie_info_text);
descriptionText = (TextView)view.findViewById(R.id.text_description);
reasonsCountText = (TextView)view.findViewById(R.id.reason_count);
reasonText1 = (TextView)view.findViewById(R.id.reason_text_1);
reasonAuthor1 = (TextView)view.findViewById(R.id.author_1);
reasonText2 = (TextView)view.findViewById(R.id.reason_text_2);
reasonAuthor2 = (TextView)view.findViewById(R.id.author_2);
commentsInputEdit = (EditText)view.findViewById(R.id.comment_input);
likeButton = (Button)view.findViewById(R.id.like_button);
saveButton = (Button)view.findViewById(R.id.save_button);
playTrailer = (Button)view.findViewById(R.id.play_trailer_button);
sendCommentButton = (Button)view.findViewById(R.id.send_button);
ignoreMovie = (ImageButton)view.findViewById(R.id.ignore_movie_imagebutton);
posterImageView = (ImageView)view.findViewById(R.id.poster_image);
userPicture1 = (ImageView)view.findViewById(R.id.user_picture_1);
userPicture2 = (ImageView)view.findViewById(R.id.user_picture_2);
tags = (TwoWayView)view.findViewById(R.id.list_view_feed_tags);
mainReasonsLayout = (RelativeLayout)view.findViewById(R.id.reasons_main_layout);
firstReasonLayout = (RelativeLayout)view.findViewById(R.id.first_reason);
secondReasonLayout = (RelativeLayout)view.findViewById(R.id.second_reason);
reasonsListLayout = (RelativeLayout)view.findViewById(R.id.reasons_list);
commentsLayout = (RelativeLayout)view.findViewById(R.id.comments_layout);
likeAndSaveButtonLayout = (LinearLayout)view
.findViewById(R.id.like_and_save_buttons_layout);
progressBar = (ProgressBar)view.findViewById(R.id.centered_progress_bar);
}
}
}
Исключение:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{42319ed8 position=1 id=-1, oldPos=0, pLpos:0 scrap tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4166)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4297)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4278)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1947)
at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:434)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1322)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:556)
at android.support.v7.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:171)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2627)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2971)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:562)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1626)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1440)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1626)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1440)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1440)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
07-30 12:48:22.688 9590-9590/com.Filmgrail.android.debug W/System.err? at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1440)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
at android.view.View.layout(View.java:15746)
at android.view.ViewGroup.layout(ViewGroup.java:4867)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2356)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2069)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6630)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
at android.view.Choreographer.doCallbacks(Choreographer.java:603)
at android.view.Choreographer.doFrame(Choreographer.java:573)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5479)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Как я могу это исправить?
android
android-recyclerview
Владимир Фишер
источник
источник
Ответы:
Эта проблема вызвана
RecyclerView
изменением данных в другом потоке. Лучший способ - это проверка доступа к данным. И это обходной путьLinearLayoutManager
.Предыдущий ответ
На самом деле была ошибка в RecyclerView, и поддержка 23.1.1 все еще не исправлена.
Для обходного пути, обратите внимание, что стеки трассировки, если мы можем поймать это
Exception
в одном из классов, могут пропустить этот сбой. Для меня я создаюLinearLayoutManagerWrapper
и переопределяюonLayoutChildren
:Затем установите его на
RecyclerView
:На самом деле поймать это исключение, и, похоже, никаких побочных эффектов еще нет.
Кроме того, если вы используете
GridLayoutManager
илиStaggeredGridLayoutManager
вы должны создать обертку для него.Примечание:
RecyclerView
может быть в неправильном внутреннем состоянии.источник
LinearLayoutManager
и переопределить это. Я буду дополнением в своем ответе.Это пример обновления данных с совершенно новым контентом. Вы можете легко изменить его в соответствии с вашими потребностями. Я решил это в моем случае, позвонив:
перед:
Это правильное решение и также упоминается в этом посте участником проекта AOSP.
источник
notifyItemRangeInserted
и имею эту проблему с некоторыми устройствами SamsungnotifyItemRangeInserted
Однажды я столкнулся с этой проблемой, и решил ее, обернув
LayoutManager
и отключив прогностическую анимацию.Вот пример:
И установите это
RecyclerView
:источник
public boolean supportsPredictiveItemAnimations() { return false; }
LinearLayoutManager
говорит, что по умолчанию ложно, но это утверждение ложно :-( Декомпилированный кодLinearLayoutManager
имеет следующее: public boolean supportsPredictiveItemAnimations () {return this.mPendingSavedState == null && this.mLastStackFromEnd == this.mStackFromEnd ;}Новый ответ: используйте DiffUtil для всех обновлений RecyclerView. Это поможет как с производительностью, так и с ошибкой выше. Посмотреть здесь
Предыдущий ответ: это сработало для меня. Ключ заключается в том, чтобы не использовать
notifyDataSetChanged()
и делать правильные вещи в правильном порядке:источник
Причины вызвали эту проблему:
РЕШЕНИЕ:
----------------- РЕШЕНИЕ 1 ---------------
Создайте пользовательский LinearLayoutManager, как показано ниже, и установите его в ReyclerView.
Затем установите RecyclerVIew Layout Manager следующим образом:
----------------- РЕШЕНИЕ 2 ---------------
Опять же, создайте собственный менеджер линейного макета следующим образом:
Затем установите RecyclerVIew Layout Manager следующим образом:
----------------- РЕШЕНИЕ 3 ---------------
----------------- РЕШЕНИЕ 4 ---------------
источник
У меня была похожая проблема.
Проблема в коде ошибки ниже:
Решение:
источник
newList.size() - 1
хотя.Согласно этой проблеме , проблема была решена и, вероятно, была выпущена в начале 2015 года . Цитата из той же ветки :
Если у вас все еще возникают проблемы с последней версией библиотеки поддержки, я бы посоветовал проверить ваши звонки
notifyXXX
(в частности, ваше использованиеnotifyDataSetChanged
) внутри вашего адаптера, чтобы убедиться, что вы придерживаетесь (несколько деликатного / неясного)RecyclerView.Adapter
контракта. Также обязательно отправляйте эти уведомления в основной поток.источник
Samsung Galaxy J3(2017) (j3y17lte), Android 8.0
У меня такая же проблема. Это было вызвано тем, что я отложил уведомление адаптера о вставке элемента.
Но
ViewHolder
попытался перерисовать некоторые данные в своем представлении, и он началRecyclerView
измерять и пересчитывать количество детей - в тот момент он падал (список элементов и его размер уже были обновлены, но адаптер еще не был уведомлен).источник
Это происходит, когда вы указываете неправильную позицию для notifyItemChanged, notifyItemRangeInserted и т. Д. Для меня:
До: (ошибочно)
После: (исправить)
источник
notifyItemRangeInserted(initialSize, mChannelItemList.size()-1);
и нетnotifyItemRangeInserted(initialSize, list.size());
?initialSize
иlist
размер. Итак, оба ваших варианта неверны.notifyItemRangeInserted(initialSize, list.size()-1);
но я не понимаю. Почему я должен уменьшить вставленный размер на единицу для itemCount?Еще одна причина, по которой эта проблема возникает, - когда вы вызываете эти методы с неправильными индексами (индексы, которых там НЕ произошло, вставляют или удаляют в них)
-notifyItemRangeRemoved
-notifyItemRemoved
-notifyItemRangeInserted
-notifyItemInserted
проверьте параметры indexe для этих методов и убедитесь, что они точные и правильные.
источник
Эта ошибка все еще не исправлена в 23.1.1, но общий обходной путь должен был бы поймать исключение.
источник
Можно подтвердить многопоточность как одну проблему, и поскольку я столкнулся с проблемой, и RxJava становится все более популярным: убедитесь, что вы используете его,
.observeOn(AndroidSchedulers.mainThread())
когда звонитеnotify[whatever changed]
Пример кода из адаптера:
источник
В моем случае каждый раз, когда я вызываю notifyItemRemoved (0), происходит сбой. Оказалось, что я установил
setHasStableIds(true)
иgetItemId
только что вернул позицию предмета. В итоге я обновил его, чтобы он возвращалhashCode()
уникальный идентификатор элемента или самоопределяемый код, что решило проблему.источник
В моем случае я столкнулся с этой проблемой из-за получения обновлений данных с сервера (я использую Firebase Firestore), и в то время как первый набор данных обрабатывается DiffUtil в фоновом режиме, другой набор данных обновляется и вызывает проблему параллелизма. запустив еще один DiffUtil.
Короче говоря, если вы используете DiffUtil в фоновом потоке, который затем возвращается в основной поток для отправки результатов в RecylerView, то у вас есть шанс получить эту ошибку, когда несколько обновлений данных происходят в короткие сроки.
Я решил это, следуя совету в этом замечательном объяснении: https://medium.com/@jonfhancock/get-threading-right-with-diffutil-423378e126d2
Просто для того, чтобы объяснить, что решение состоит в том, чтобы отправить обновления, пока текущее работает в Deque. Затем deque может запускать ожидающие обновления после завершения текущего, следовательно, обрабатывая все последующие обновления, но также избегая ошибок несогласованности!
Надеюсь, это поможет, потому что этот заставил меня почесать голову!
источник
Проблема возникла у меня только тогда, когда:
Я создал Адаптер с пустым списком . Затем я вставил предметы и позвонил
notifyItemRangeInserted
.Решение:
Я решил это, создав адаптер только после того, как у меня есть первый кусок данных и сразу его инициализировал. Следующий блок может быть вставлен и
notifyItemRangeInserted
вызван без проблем.источник
notifyItemRangeInserted
, но такого исключения там никогда не было.Моя проблема заключалась в том, что, хотя я очищал оба списка массивов, содержащих модель данных для представления переработчика, я не уведомлял адаптер об этом изменении, поэтому он имел устаревшие данные из предыдущей модели. Что вызвало недоразумение относительно позиции держателя вида. Чтобы исправить это, всегда сообщайте адаптеру, что набор данных изменился, прежде чем обновлять снова.
источник
В моем случае я изменял данные, ранее находившиеся в потоке, с помощью mRecyclerView.post (новый Runnable ...), а затем снова изменял данные в потоке пользовательского интерфейса, что вызывало несогласованность.
источник
Ошибка может быть вызвана тем, что ваши изменения не соответствуют тому, что вы уведомляете. В моем случае:
Что я, конечно, должен был сделать:
источник
В моем случае проблема заключалась в том, что я использовал notifyDataSetChanged, когда количество вновь загруженных данных было меньше, чем исходные данные. Этот подход помог мне:
источник
notifyDataSetChanged
зависит от новых данных? Я думал, что это обновит весь список.Я столкнулся с той же проблемой.
Мое приложение использует компоненты навигации с фрагментом, содержащим мой recyclerView. Мой список отображался нормально при первой загрузке фрагмента ... но при удалении и возвращении произошла эта ошибка.
При перемещении по фрагменту жизненный цикл фрагмента проходил только через onDestroyView, а по возвращении он начинался с onCreateView. Однако, мой адаптер был инициализирован в onCreate фрагмента и не был повторно инициализирован при возврате.
Исправление состояло в том, чтобы инициализировать адаптер в onCreateView.
Надеюсь, что это может кому-то помочь.
источник
Я получил эту ошибку, потому что я несколько раз ошибочно вызывал метод для удаления определенной строки из моего окна повторного использования. У меня был метод как:
Я случайно вызывал этот метод три раза вместо одного, поэтому второй раз
loc
был равен -1, и при попытке удалить его была выдана ошибка. Эти два исправления должны были гарантировать, что метод был вызван только один раз, а также добавить проверку работоспособности следующим образом:источник
У меня возникла та же проблема, и я прочитал, что это произошло только в телефонах Samsung ... Но реальность показала, что это происходит во многих брендах.
После тестирования я понял, что это происходит только тогда, когда вы быстро прокручиваете RecyclerView и затем возвращаетесь либо с помощью кнопки «Назад», либо с помощью кнопки «Вверх». Поэтому я поместил внутри кнопку «Вверх» и нажал на кнопку нижеприведенного фрагмента:
С этим решением вы просто загружаете новый Arraylist в адаптер и новый адаптер в recyclerView, а затем завершаете работу.
Надеюсь, это поможет кому-то
источник
Я получил эту ошибку, потому что я дважды вызывал «notifyItemInserted» по ошибке.
источник
В моем случае в списке было более 5000 наименований. Моя проблема заключалась в том, что при прокрутке представления рециркулятора иногда вызывается «onBindViewHolder», а метод «myCustomAddItems» изменяет список.
Мое решение состояло в том, чтобы добавить «synchronized (syncObject) {}» ко всем методам, которые изменяют список данных. Таким образом, в любой момент времени только один метод может прочитать этот список.
источник
В моем случае данные адаптера изменились. И я был неправильно использовать notifyItemInserted () для этих изменений. Когда я использую notifyItemChanged, ошибка исчезла.
источник
Я столкнулся с той же проблемой, когда удалял и обновлял элементы в списке ... После нескольких дней исследований я думаю, что наконец нашел решение.
То, что вам нужно сделать, это сначала сделать все
notifyItemChanged
из вашего списка и только потом делать всеnotifyItemRemoved
в порядке убыванияЯ надеюсь, что это поможет людям, которые сталкиваются с той же проблемой ...
источник
Я использую Курсор, поэтому я не могу использовать DiffUtils, как предложено в популярных ответах. Чтобы это работало для меня, я отключаю анимацию, когда список не простаивает. Это расширение, которое решает эту проблему:
Затем вы можете обновить свой адаптер, как это
источник
Если проблема возникает после мультитач, вы можете отключить мультитач с
в файле макета.
источник
Если ваши данные сильно меняются, вы можете использовать
или некоторые отдельные элементы в вашем наборе данных изменяются, вы можете использовать
Для подробного использования методов вы можете обратиться к документу , пытаясь не использовать его напрямую
mAdapter.notifyDataSetChanged()
.источник
notifyItemRangeChanged
также вызывает тот же сбой.