Tengo una vista de reciclador que funciona perfectamente en todos los dispositivos, excepto Samsung. En Samsung, tengo
java.lang.IndexOutOfBoundsException: Inconsistencia detectada. Posición del adaptador del soporte de la vista no válida
cuando vuelvo al fragmento con la vista de reciclador de otra actividad.
Código del adaptador:
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);
}
}
}
Excepción:
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)
¿Cómo puedo arreglar esto?
android
android-recyclerview
Владимир Фишер
fuente
fuente
Respuestas:
Este problema es causado por
RecyclerView
datos modificados en diferentes hilos. La mejor manera es verificar todo el acceso a datos. Y se está resolviendo una solución alternativaLinearLayoutManager
.Respuesta anterior
En realidad, hubo un error en RecyclerView y el soporte 23.1.1 todavía no se solucionó.
Para una solución alternativa, tenga en cuenta que las pilas de retroceso, si podemos atrapar esto
Exception
en alguna clase, puede omitir este bloqueo. Para mí, creoLinearLayoutManagerWrapper
y anulo elonLayoutChildren
:Luego configúrelo en
RecyclerView
:En realidad, capta esta excepción y parece que todavía no hay ningún efecto secundario.
Además, si usa
GridLayoutManager
oStaggeredGridLayoutManager
debe crear un contenedor para ello.Aviso:
RecyclerView
puede estar en un estado interno incorrecto.fuente
LinearLayoutManager
ay anule esto. Haré una adición en mi respuesta.Este es un ejemplo para actualizar datos con contenido completamente nuevo. Puede modificarlo fácilmente para adaptarlo a sus necesidades. Resolví esto en mi caso llamando:
antes de:
Esta es la solución correcta y también es mencionada en esta publicación por un miembro del proyecto AOSP.
fuente
notifyItemRangeInserted
y tengo este problema con algunos dispositivos SamsungnotifyItemRangeInserted
Enfrenté este problema una vez, y lo resolví envolviendo el
LayoutManager
y desactivando las animaciones predictivas.Aquí un ejemplo:
Y configúrelo en
RecyclerView
:fuente
public boolean supportsPredictiveItemAnimations() { return false; }
LinearLayoutManager
dice que el valor predeterminado es falso, pero esa declaración es falsa :-( El código descompilado paraLinearLayoutManager
tiene esto: public boolean supportsPredictiveItemAnimations () {return this.mPendingSavedState == null && this.mLastStackFromEnd == this.mStackFromEnd ;}Nueva respuesta: use DiffUtil para todas las actualizaciones de RecyclerView. Esto ayudará con el rendimiento y el error anterior. Mira aquí
Respuesta anterior: Esto funcionó para mí. La clave es no usar
notifyDataSetChanged()
y hacer las cosas correctas en el orden correcto:fuente
Las razones causaron este problema:
SOLUCIÓN:
----------------- SOLUCIÓN 1 ---------------
Cree un LinearLayoutManager personalizado como el siguiente y configúrelo en ReyclerView
Luego configure RecyclerVIew Layout Manager de la siguiente manera:
----------------- SOLUCIÓN 2 ---------------
Nuevamente, cree un Administrador de diseño lineal personalizado de la siguiente manera:
Luego configure RecyclerVIew Layout Manager de la siguiente manera:
----------------- SOLUCIÓN 3 ---------------
----------------- SOLUCIÓN 4 ---------------
fuente
Tuve un problema similar.
Problema en el código de error a continuación:
Solución:
fuente
newList.size() - 1
embargo, no estoy seguro de por qué no podemos usarlo .De acuerdo con este problema , el problema se ha resuelto y probablemente se publicó en algún momento cerca del comienzo de 2015. Una cita de ese mismo hilo :
Si todavía tiene problemas con una versión reciente de la biblioteca de soporte, le sugiero que revise sus llamadas
notifyXXX
(específicamente, su uso denotifyDataSetChanged
) dentro de su adaptador, para asegurarse de que cumple con elRecyclerView.Adapter
contrato (algo delicado / oscuro) . También asegúrese de emitir esas notificaciones en el hilo principal.fuente
Samsung Galaxy J3(2017) (j3y17lte), Android 8.0
Yo tuve el mismo problema. Fue causado porque retrasé la notificación del adaptador sobre la inserción del elemento.
Pero
ViewHolder
trató de volver a dibujar algunos datos a su vista y comenzó aRecyclerView
medir y volver a contar el recuento de niños; en ese momento se bloqueó (la lista de elementos y su tamaño ya se actualizaron, pero el adaptador aún no se notificó).fuente
Esto sucede cuando especifica la posición incorrecta para notifyItemChanged, notifyItemRangeInserted, etc. Para mí:
Antes: (erróneo)
Después: (correcto)
fuente
notifyItemRangeInserted(initialSize, mChannelItemList.size()-1);
y nonotifyItemRangeInserted(initialSize, list.size());
?initialSize
ylist
dimensionaste. Entonces, ambas variantes están mal.notifyItemRangeInserted(initialSize, list.size()-1);
pero no lo entiendo. ¿Por qué tengo que reducir el tamaño insertado en uno para el itemCount?Otra razón por la que ocurre este problema es cuando llama a estos métodos con índices incorrectos (los índices que NO han sucedido se insertan o eliminan en ellos)
-notifyItemRangeRemoved
-notifyItemRemoved
-notifyItemRangeInserted
-notifyItemInserted
verifique los parámetros de indexación de estos métodos y asegúrese de que sean precisos y correctos.
fuente
Este error aún no se solucionó en 23.1.1, pero una solución común sería detectar la excepción.
fuente
Puede confirmar el enhebrado como un problema y desde que me encontré con el problema y RxJava se está volviendo cada vez más popular: asegúrese de usarlo
.observeOn(AndroidSchedulers.mainThread())
cada vez que llamenotify[whatever changed]
ejemplo de código del adaptador:
fuente
En mi caso, cada vez que llamo a notifyItemRemoved (0), se bloquea. Resultó que configuré
setHasStableIds(true)
ygetItemId
acabo de devolver la posición del artículo. Terminé actualizándolo para devolver el ítemhashCode()
o la identificación única autodefinida, lo que resolvió el problema.fuente
En mi caso, recibí este problema debido a que recibí actualizaciones de datos del servidor (estoy usando Firebase Firestore) y mientras DiffUtil procesa el primer conjunto de datos en segundo plano, aparece otro conjunto de actualización de datos que causa un problema de concurrencia iniciando otro DiffUtil.
En resumen, si está utilizando DiffUtil en un subproceso en segundo plano que luego regresa al subproceso principal para enviar los resultados al RecylerView, entonces tiene la posibilidad de obtener este error cuando llegan varias actualizaciones de datos en poco tiempo.
Resolví esto siguiendo los consejos de esta maravillosa explicación: https://medium.com/@jonfhancock/get-threading-right-with-diffutil-423378e126d2
Solo para explicar que la solución es enviar las actualizaciones mientras la actual se ejecuta en Deque. ¡El deque puede ejecutar las actualizaciones pendientes una vez que finalice la actual, por lo tanto, manejar todas las actualizaciones posteriores pero también evitar errores de inconsistencia!
¡Espero que esto ayude porque este me hizo rascarme la cabeza!
fuente
Se produjo un problema para mí solo cuando:
Creé el adaptador con una lista vacía . Luego inserté elementos y llamé
notifyItemRangeInserted
.Solución:
Resolví esto creando el Adaptador solo después de tener la primera porción de datos e inicializándolo con él de inmediato. El siguiente fragmento se podría insertar y
notifyItemRangeInserted
llamar sin ningún problema.fuente
notifyItemRangeInserted
, pero nunca tuve esta excepción allí.Mi problema fue que, aunque borré la lista de la matriz que contiene el modelo de datos para la vista del reciclador, no notifiqué al adaptador ese cambio, por lo que tenía datos obsoletos del modelo anterior. Lo que causó la confusión sobre la posición del titular de la vista. Para solucionar esto, siempre notifique al adaptador que el conjunto de datos ha cambiado antes de actualizar nuevamente.
fuente
En mi caso, estaba cambiando los datos previamente dentro de un hilo con mRecyclerView.post (nuevo Runnable ...) y luego volví a cambiar los datos en el hilo de la interfaz de usuario, lo que causó inconsistencia.
fuente
El error puede deberse a que sus cambios son inconsistentes con lo que está notificando. En mi caso:
Lo que, por supuesto, tuve que hacer:
fuente
En mi caso, el problema era que usé notifyDataSetChanged cuando la cantidad de datos recién cargados era menor que los datos iniciales. Este enfoque me ayudó:
fuente
notifyDataSetChanged
depende de nuevos datos? Pensé que actualizaría toda la lista.Tuve el mismo problema.
Mi aplicación utiliza componentes de navegación con un fragmento que contiene mi recyclerView. Mi lista se mostró bien la primera vez que se cargó el fragmento ... pero al navegar y regresar, se produjo este error.
Al navegar lejos, el ciclo de vida del fragmento pasó solo por onDestroyView y al regresar comenzó en onCreateView. Sin embargo, mi adaptador se inicializó en el fragmento onCreate y no se reinicializó al regresar.
La solución fue inicializar el adaptador en onCreateView.
Espero que esto pueda ayudar a alguien.
fuente
Recibí este error porque estaba llamando por error a un método para eliminar una fila específica de mi vista de reciclador varias veces. Tenía un método como:
Accidentalmente estaba llamando a este método tres veces en lugar de una vez, por lo que la segunda vez
loc
fue -1 y se produjo el error cuando intentó eliminarlo. Las dos soluciones fueron para garantizar que el método solo se llamara una vez, y también para agregar un control de cordura como este:fuente
Tengo el mismo problema y he leído que esto sucedió solo en teléfonos Samsung ... Pero la realidad mostró que esto sucede en muchas marcas.
Después de la prueba, me di cuenta de que esto sucede solo cuando se desplaza rápidamente el RecyclerView y luego retrocede con el botón Atrás o el botón Arriba. Así que puse dentro el botón Arriba y presioné el fragmento a continuación:
Con esta solución, simplemente carga una nueva Arraylist en el adaptador y un nuevo adaptador en recyclerView y luego finaliza la actividad.
Espero que ayude a alguien
fuente
Recibí este error porque estaba llamando a "notifyItemInserted" dos veces por error.
fuente
En mi caso, he tenido más de 5000 artículos en la lista. Mi problema fue que al desplazar la vista del reciclador, a veces se llama al "onBindViewHolder" mientras el método "myCustomAddItems" está alterando la lista.
Mi solución fue agregar "sincronizado (syncObject) {}" a todos los métodos que alteran la lista de datos. De esta manera, en cualquier momento, solo un método puede leer esta lista.
fuente
En mi caso, los datos del adaptador cambiaron. Y utilicé incorrectamente notifyItemInserted () para estos cambios. Cuando uso notifyItemChanged, el error ha desaparecido.
fuente
Me encontré con el mismo problema cuando eliminé y actualicé los elementos de la lista ... Después de días de investigación, creo que finalmente encontré una solución.
Lo que debe hacer es primero hacer toda
notifyItemChanged
su lista y solo luego hacer todonotifyItemRemoved
en orden descendenteEspero que esto ayude a las personas que se encuentran con el mismo problema ...
fuente
Estoy usando un cursor, por lo que no puedo usar los DiffUtils como se propone en las respuestas populares. Para que funcione para mí, deshabilito las animaciones cuando la lista no está inactiva. Esta es la extensión que soluciona este problema:
Entonces puedes actualizar tu adaptador así
fuente
Si el problema ocurre después de la función multitáctil, puede desactivarla con
en el archivo de diseño.
fuente
Si sus datos cambian mucho, puede usar
o algunos elementos individuales en su conjunto de datos cambian, puede usar
Para el uso detallado de los métodos, puede consultar el documento , de alguna manera, intente no usarlo directamente
mAdapter.notifyDataSetChanged()
.fuente
notifyItemRangeChanged
también produce el mismo bloqueo.