J'ai une vue de recycleur qui fonctionne parfaitement sur tous les appareils sauf Samsung. Sur Samsung, je reçois
java.lang.IndexOutOfBoundsException: incohérence détectée. Position de l'adaptateur du support de vue non valide
quand je reviens au fragment avec la vue recycleur d'une autre activité.
Code adaptateur:
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);
}
}
}
Exception:
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)
Comment puis-je réparer cela?
android
android-recyclerview
Владимир Фишер
la source
la source
Réponses:
Ce problème est dû aux
RecyclerView
données modifiées dans un thread différent. La meilleure façon est de vérifier tous les accès aux données. Et une solution de contournement se termineLinearLayoutManager
.Réponse précédente
Il y avait en fait un bogue dans RecyclerView et le support 23.1.1 n'était toujours pas corrigé.
Pour une solution de contournement, notez que les piles de backtrace, si nous pouvons attraper ce
Exception
dans une classe, cela peut sauter ce plantage. Pour moi, je crée unLinearLayoutManagerWrapper
et remplace leonLayoutChildren
:Réglez-le ensuite sur
RecyclerView
:En fait, saisissez cette exception et ne semble pas encore avoir d'effet secondaire.
De plus, si vous utilisez
GridLayoutManager
ouStaggeredGridLayoutManager
vous devez créer un wrapper pour cela.Remarque: le
RecyclerView
peut être dans un mauvais état interne.la source
LinearLayoutManager
et remplacer cela. Je ferai un ajout dans ma réponse.Ceci est un exemple d'actualisation de données avec un contenu complètement nouveau. Vous pouvez facilement le modifier pour l'adapter à vos besoins. J'ai résolu cela dans mon cas en appelant:
avant:
C'est la bonne solution et est également mentionnée dans cet article par un membre du projet AOSP.
la source
notifyItemRangeInserted
et n'ai pas ce problème avec certains appareils SamsungnotifyItemRangeInserted
J'ai fait face à ce problème une fois, et je l'ai résolu en enveloppant le
LayoutManager
animations prédictives et en les désactivant.Voici un exemple:
Et réglez-le sur
RecyclerView
:la source
public boolean supportsPredictiveItemAnimations() { return false; }
LinearLayoutManager
indique que la valeur par défaut est false, mais cette déclaration est fausse :-( Le code décompilé pourLinearLayoutManager
a ceci: public boolean supportsPredictiveItemAnimations () {return this.mPendingSavedState == null && this.mLastStackFromEnd == this.mStackFromEnd ;}Nouvelle réponse: utilisez DiffUtil pour toutes les mises à jour de RecyclerView. Cela contribuera à la fois aux performances et au bogue ci-dessus. Vois ici
Réponse précédente: Cela a fonctionné pour moi. La clé est de ne pas utiliser
notifyDataSetChanged()
et de faire les bonnes choses dans le bon ordre:la source
Les raisons ont provoqué ce problème:
SOLUTION:
----------------- SOLUTION 1 ---------------
Créez un LinearLayoutManager personnalisé comme suit et définissez-le sur ReyclerView
Ensuite, définissez RecyclerVIew Layout Manager comme suit:
----------------- SOLUTION 2 ---------------
Encore une fois, créez un gestionnaire de disposition linéaire personnalisé comme suit:
Ensuite, définissez RecyclerVIew Layout Manager comme suit:
----------------- SOLUTION 3 ---------------
----------------- SOLUTION 4 ---------------
la source
J'avais un problème similaire.
Problème dans le code d'erreur ci-dessous:
Solution:
la source
newList.size() - 1
.Selon ce problème , le problème a été résolu et a probablement été publié quelque temps vers le début de 2015. Une citation de ce même fil :
Si vous rencontrez toujours des problèmes avec une version récente de la bibliothèque de support, je vous suggère de revoir vos appels à
notifyXXX
(spécifiquement, votre utilisation denotifyDataSetChanged
) à l'intérieur de votre adaptateur, pour vous assurer que vous respectez leRecyclerView.Adapter
contrat (quelque peu délicat / obscur) . Assurez-vous également d'émettre ces notifications sur le fil principal.la source
Samsung Galaxy J3(2017) (j3y17lte), Android 8.0
J'ai eu le même problème. Cela est dû au fait que j'ai retardé la notification de l'adaptateur à propos de l'insertion d'élément.
Mais a
ViewHolder
essayé de redessiner certaines données dans sa vue et il a commencé àRecyclerView
mesurer et à recompter le nombre d'enfants - à ce moment, il s'est écrasé (la liste des articles et sa taille ont déjà été mises à jour, mais l'adaptateur n'a pas encore été informé).la source
Cela se produit lorsque vous spécifiez la position incorrecte pour notifyItemChanged, notifyItemRangeInserred, etc. Pour moi:
Avant: (erroné)
Après: (correct)
la source
notifyItemRangeInserted(initialSize, mChannelItemList.size()-1);
et nonnotifyItemRangeInserted(initialSize, list.size());
?initialSize
et lalist
taille. Donc, vos deux variantes sont fausses.notifyItemRangeInserted(initialSize, list.size()-1);
mais je ne comprends pas. Pourquoi dois-je réduire la taille insérée d'une unité pour itemCount?une autre raison pour laquelle ce problème se produit est lorsque vous appelez ces méthodes avec des index incorrects (index qui ne se sont PAS produits, insérez-les ou supprimez-les)
-notifyItemRangeRemoved
-notifyItemRemoved
-notifyItemRangeInserred
-notifyItemInserred
vérifiez les paramètres d'indexation de ces méthodes et assurez-vous qu'ils sont précis et corrects.
la source
Ce bogue n'est toujours pas corrigé dans 23.1.1, mais une solution de contournement courante consisterait à intercepter l'exception.
la source
Peut confirmer le filetage comme un problème et depuis que j'ai rencontré le problème et que RxJava devient de plus en plus populaire: assurez-vous que vous utilisez
.observeOn(AndroidSchedulers.mainThread())
chaque fois que vous appeleznotify[whatever changed]
exemple de code de l'adaptateur:
la source
Dans mon cas, chaque fois que j'appelle notifyItemRemoved (0), il se bloquait. Il s'est avéré que j'ai défini
setHasStableIds(true)
etgetItemId
je viens de retourner la position de l'article. J'ai fini par le mettre à jour pour renvoyer l'hashCode()
ID unique de l'article ou défini par l'utilisateur, ce qui a résolu le problème.la source
Dans mon cas, j'obtenais ce problème en raison de l'obtention de mises à jour de données du serveur (j'utilise Firebase Firestore) et tandis que le premier ensemble de données est traité par DiffUtil en arrière-plan, un autre ensemble de mise à jour de données vient et provoque un problème de concurrence en lançant un autre DiffUtil.
En bref, si vous utilisez DiffUtil sur un thread d'arrière-plan qui revient ensuite au thread principal pour envoyer les résultats au RecylerView, vous courez la chance d'obtenir cette erreur lorsque plusieurs mises à jour de données arrivent en peu de temps.
J'ai résolu cela en suivant les conseils de cette merveilleuse explication: https://medium.com/@jonfhancock/get-threading-right-with-diffutil-423378e126d2
Pour expliquer la solution, il suffit de pousser les mises à jour pendant que la version actuelle s'exécute sur un Deque. Le deque peut ensuite exécuter les mises à jour en attente une fois la mise à jour terminée, gérant ainsi toutes les mises à jour suivantes mais en évitant également les erreurs d'incohérence!
J'espère que cela aide, car celui-ci m'a fait me gratter la tête!
la source
Le problème ne s'est produit pour moi que lorsque:
J'ai créé l'adaptateur avec un liste vide . Ensuite, j'ai inséré des éléments et appelé
notifyItemRangeInserted
.Solution:
J'ai résolu ce problème en créant l'adaptateur uniquement après avoir le premier bloc de données et en l'initialisant immédiatement. Le morceau suivant pourrait alors être inséré et
notifyItemRangeInserted
appelé sans problème.la source
notifyItemRangeInserted
, mais je n'ai jamais eu cette exception là-bas.Mon problème était que même si j'effaçais à la fois la liste des tableaux contenant le modèle de données pour la vue du recycleur, je n'avais pas notifié l'adaptateur de ce changement, donc il avait des données périmées du modèle précédent. Ce qui a provoqué la confusion sur la position du support de vue. Pour résoudre ce problème, informez toujours l'adaptateur que l'ensemble de données a été modifié avant de le mettre à jour à nouveau.
la source
Dans mon cas, je modifiais les données précédemment dans un thread avec mRecyclerView.post (nouveau Runnable ...), puis à nouveau plus tard, des données modifiées dans le thread d'interface utilisateur, ce qui a provoqué une incohérence.
la source
L'erreur peut être due au fait que vos modifications ne correspondent pas à ce que vous notifiez. Dans mon cas:
Ce que je devais bien sûr faire:
la source
Dans mon cas, le problème était que j'utilisais notifyDataSetChanged lorsque la quantité de données nouvellement chargées était inférieure aux données initiales. Cette approche m'a aidé:
la source
notifyDataSetChanged
dépend de nouvelles données? Je pensais que cela rafraîchirait toute la liste.J'ai rencontré le même problème.
Mon application utilise des composants de navigation avec un fragment contenant ma recyclerView. Ma liste s'est bien affichée la première fois que le fragment a été chargé ... mais lors de la navigation et du retour, cette erreur s'est produite.
Lorsque vous vous éloignez, le cycle de vie du fragment ne passe que par onDestroyView et lors du retour, il démarre à onCreateView. Cependant, mon adaptateur a été initialisé dans le onCreate du fragment et ne s'est pas réinitialisé lors du retour.
Le correctif consistait à initialiser l'adaptateur dans onCreateView.
J'espère que cela peut aider quelqu'un.
la source
J'ai eu cette erreur parce que j'appelais par erreur une méthode pour supprimer plusieurs fois une ligne spécifique de ma vue de recyclage. J'avais une méthode comme:
J'appelais accidentellement cette méthode trois fois au lieu d'une fois, donc la deuxième fois
loc
était -1 et l'erreur a été donnée lors de la tentative de suppression. Les deux correctifs devaient garantir que la méthode n'était appelée qu'une seule fois, et également ajouter un contrôle d'intégrité comme celui-ci:la source
J'ai eu le même problème et j'ai lu que cela ne s'était produit que sur les téléphones Samsung ... Mais la réalité a montré que cela se produit dans de nombreuses marques.
Après les tests, je me suis rendu compte que cela ne se produit que lorsque vous faites défiler rapidement le RecyclerView, puis que vous revenez soit avec le bouton de retour soit avec le bouton Haut. J'ai donc mis à l'intérieur du bouton Haut et on a appuyé sur l'extrait ci-dessous:
Avec cette solution, vous chargez simplement un nouvel Arraylist dans l'adaptateur et un nouvel adaptateur dans recyclerView, puis vous terminez l'activité.
J'espère que cela aide quelqu'un
la source
J'ai eu cette erreur parce que j'appelais "notifyItemInsert" deux fois par erreur.
la source
Dans mon cas, j'ai eu plus de 5000 éléments dans la liste. Mon problème était que lors du défilement de la vue du recycleur, parfois la méthode «onBindViewHolder» était appelée tandis que la méthode «myCustomAddItems» modifiait la liste.
Ma solution a été d'ajouter "synchronized (syncObject) {}" à toutes les méthodes qui modifient la liste des données. De cette façon, à tout moment, une seule méthode peut lire cette liste.
la source
Dans mon cas, les données de l'adaptateur ont changé. Et j'ai utilisé à tort notifyItemInserred () pour ces modifications. Lorsque j'utilise notifyItemChanged, l'erreur a disparu.
la source
J'ai rencontré le même problème lorsque j'ai supprimé et mis à jour des éléments de la liste ... Après des jours d'enquête, je pense avoir finalement trouvé une solution.
Ce que vous devez faire, c'est d'abord faire toute
notifyItemChanged
votre liste et ensuite seulement faire toutnotifyItemRemoved
dans un ordre décroissantJ'espère que cela aidera les gens qui rencontrent le même problème ...
la source
J'utilise un curseur donc je ne peux pas utiliser les DiffUtils comme proposé dans les réponses populaires. Afin de le faire fonctionner pour moi, je désactive les animations lorsque la liste n'est pas inactive. Il s'agit de l'extension qui résout ce problème:
Ensuite, vous pouvez mettre à jour votre adaptateur comme ça
la source
Si le problème se produit après le multi-touch, vous pouvez désactiver le multi-touch avec
dans le fichier de mise en page.
la source
Si vos données changent beaucoup, vous pouvez utiliser
ou certains éléments dans vos modifications de jeu de données, vous pouvez utiliser
Pour une utilisation détaillée des méthodes, vous pouvez vous référer au document , en quelque sorte, essayez de ne pas l'utiliser directement
mAdapter.notifyDataSetChanged()
.la source
notifyItemRangeChanged
produit également le même plantage.