recyclerview make how dependency create card and android-recyclerview recycler-adapter

android recyclerview - make - Vista de reciclador: Inconsistencia detectada. El soporte de la vista no es vĂ¡lido. ViewViewHolder



recyclerview android kotlin (9)

Recycler View Inconsistency Detected error, que aparece mientras se desplaza rápidamente o se desplaza mientras carga más elementos.

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

Adaptador

public class DataAdapter extends RecyclerView.Adapter { private final int VIEW_ITEM = 1; private final int VIEW_PROG = 0; private List<Feed> mFeed; // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 5; private int lastVisibleItem, totalItemCount; private boolean loading; private OnLoadMoreListener onLoadMoreListener; public DataAdapter(List<Feed> feeds, RecyclerView recyclerView) { mFeed = feeds; if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView .getLayoutManager(); recyclerView .addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); totalItemCount = linearLayoutManager.getItemCount(); lastVisibleItem = linearLayoutManager .findLastVisibleItemPosition(); if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) { // End has been reached // Do something if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); } loading = true; } } }); } } @Override public int getItemViewType(int position) { return mFeed.get(position) == null ? VIEW_PROG : VIEW_ITEM; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder vh; if (viewType == VIEW_ITEM) { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.list_row, parent, false); vh = new StudentViewHolder(v); } else { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.progress_item, parent, false); vh = new ProgressViewHolder(v); } return vh; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof StudentViewHolder) { Feed singleStudent= (Feed) mFeed.get(position); ((StudentViewHolder) holder).tvName.setText(singleStudent.getTitle()); ((StudentViewHolder) holder).student= singleStudent; } else { ProgressViewHolder.PROGRESS_BAR.setIndeterminate(true); } } public void setLoaded() { loading = false; } public void addFeed(Feed feed) { mFeed.add(feed); //mFeed.addAll(0, (Collection<? extends Feed>) feed); notifyItemInserted(mFeed.size()); //notifyItemRangeInserted(0,mFeed.size()); notifyDataSetChanged(); //notifyItemInserted(mFeed.size()); //setLoaded(); //notifyItemInserted(mFeed.size()); } public void removeAll(){ mFeed.clear(); notifyDataSetChanged(); } @Override public int getItemCount() { return mFeed.size(); } public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { this.onLoadMoreListener = onLoadMoreListener; } public static class StudentViewHolder extends RecyclerView.ViewHolder { public TextView tvName; public Feed student; public StudentViewHolder(View v) { super(v); tvName = (TextView) v.findViewById(R.id.tvName); //tvEmailId = (TextView) v.findViewById(R.id.tvEmailId); } } public static class ProgressViewHolder extends RecyclerView.ViewHolder { //public ProgressBar progressBar; public static ProgressBar PROGRESS_BAR; public ProgressViewHolder(View v) { super(v); PROGRESS_BAR = (ProgressBar) v.findViewById(R.id.progressBar1); // progressBar = (ProgressBar) v.findViewById(R.id.progressBar1); } } }

Actividad

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener { private Toolbar toolbar; private TextView tvEmptyView; private RecyclerView mRecyclerView; private DataAdapter mAdapter; private LinearLayoutManager mLayoutManager; private RestManager mManager; private List<Feed> mFeed; SwipeRefreshLayout mSwipeRefreshLayout; protected Handler handler; private int currentPage=1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toolbar = (Toolbar) findViewById(R.id.toolbar); tvEmptyView = (TextView) findViewById(R.id.empty_view); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); mSwipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); mSwipeRefreshLayout.setOnRefreshListener(this); //studentList = new ArrayList<Student>(); mFeed = new ArrayList<Feed>(); handler = new Handler(); if (toolbar != null) { setSupportActionBar(toolbar); getSupportActionBar().setTitle("Android Students"); } mManager = new RestManager(); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); // use a linear layout manager mRecyclerView.setLayoutManager(mLayoutManager); // create an Object for Adapter mAdapter = new DataAdapter(mFeed,mRecyclerView); // set the adapter object to the Recyclerview mRecyclerView.setAdapter(mAdapter); // mAdapter.notifyDataSetChanged(); loadData(false); // if (mFeed.isEmpty()) { // mRecyclerView.setVisibility(View.GONE); // tvEmptyView.setVisibility(View.VISIBLE); // // } else { // mRecyclerView.setVisibility(View.VISIBLE); // tvEmptyView.setVisibility(View.GONE); // } mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { //add null , so the adapter will check view_type and show progress bar at bottom mFeed.add(null); mAdapter.notifyItemInserted(mFeed.size() - 1); handler.postDelayed(new Runnable() { @Override public void run() { // remove progress item mFeed.remove(mFeed.size() - 1); // mAdapter.notifyItemRemoved(mFeed.size()); //add items one by one int start = mFeed.size(); currentPage++; Log.d("CurrentPage", String.valueOf(currentPage)); Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1); listCall.enqueue(new Callback<Results>() { @Override public void onResponse(Call<Results> call, Response<Results> response) { mSwipeRefreshLayout.setRefreshing(false); if (response.isSuccess()) { if (response.body() != null) { Results feedList = response.body(); // List<Results> newUsers = response.body(); Log.d("Retrofut", String.valueOf(feedList)); for (int i = 0; i < feedList.results.size(); i++) { Feed feed = feedList.results.get(i); // mFeed.add(feed); mAdapter.addFeed(feed); // mAdapter.notifyDataSetChanged(); //mAdapter.notifyItemInserted(mFeed.size()); } // mAdapter.notifyDataSetChanged(); } } } @Override public void onFailure(Call<Results> call, Throwable t) { Log.d("Retrofut", "Error"); mFeed.remove(mFeed.size() - 1); mAdapter.notifyItemRemoved(mFeed.size()); mAdapter.setLoaded(); mSwipeRefreshLayout.setRefreshing(false); } }); // for (int i = 1; i <= 20; i++) { // studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com")); // // } mAdapter.setLoaded(); //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged(); } }, 2000); } }); } // load initial data private void loadData(final boolean removePreData) { Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1); listCall.enqueue(new Callback<Results>() { @Override public void onResponse(Call<Results> call, Response<Results> response) { if (response.isSuccess()) { if (response.body() != null) { // if(removePreData) mAdapter.removeAll(); Results feedList = response.body(); Log.d("Retrofut", String.valueOf(feedList)); for (int i = 0; i < feedList.results.size(); i++) { Feed feed = feedList.results.get(i); // mFeed.add(feed); //mAdapter.notifyDataSetChanged(); mAdapter.addFeed(feed); } mSwipeRefreshLayout.setRefreshing(false); } } } @Override public void onFailure(Call<Results> call, Throwable t) { Log.d("Retrofut", String.valueOf(t)); mFeed.remove(mFeed.size() - 1); mAdapter.notifyItemRemoved(mFeed.size()); mAdapter.setLoaded(); mSwipeRefreshLayout.setRefreshing(false); } } ); // for (int i = 1; i <= 20; i++) { // studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com")); // // } mSwipeRefreshLayout.setRefreshing(true); } @Override public void onRefresh() { mFeed.clear(); mAdapter.notifyDataSetChanged(); loadData(true); currentPage=1; } }


En mi caso, lo estaba haciendo como notifyItemInserted(position); Eso me causó este problema, luego lo usé y funcionó perfectamente. notifyItemRangeInserted(startIndex,endIndex);


Este problema es un error conocido de la vista de reciclaje. La mejor solución es

borre la lista cada vez antes de actualizar la vista de reciclaje

Para solucionar este problema, simplemente llame a notifyDataSetChanged () con la lista vacía antes de actualizar la vista de reciclaje.

Por ejemplo

//Method for refresh recycle view if (!yourList.isEmpty()) yourList.clear(); //The list for update recycle view adapter.notifyDataSetChanged();


Intente cambiar private List<Feed> mFeed; a private ArrayList<Feed> mFeed;

Y en tu constructor cambia mFeed = feeds a

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

Entonces puedes agregar normalmente así:

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

Así que cambiar List a ArrayList resolvió mi problema. Creo que es porque List es una clase abstracta y los métodos add , remove , clear , etc. no se implementan allí. Por lo tanto, cuando define una Lista ( private ArrayList<Feed> mFeed; ) y la inicia con otra Lista ( mFeed = feeds ;) llamando a mFeed.add(feed) no hace nada y hace que recyclerView arroje una excepción.


Se ve similar con el bug conocido de Android

Hay bastante feo, pero el enfoque de trabajo

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

Para mí funciona sin ningún efecto secundario.


Tuve este problema al desplazarme rápidamente a través de mi RecyclerView sin fin / paginación. La raíz de mi problema vino del hecho de que tenía un elemento de "encabezado" al principio de la lista, este elemento de encabezado no formaba parte de la fuente de datos, solo se insertaba al principio de la lista de adapter . Así que al desplazarme rápidamente y agregar nuevas páginas de elementos al RecyclerView Adapter y notificar al adapter que se habían insertado nuevos datos, no estaba teniendo en cuenta el elemento de encabezado adicional, lo que hacía que el tamaño de la lista del adaptador fuera incorrecto ... y causara esta excepción ...

En resumen, si usa un encabezado / pie de página en nuestro adaptador RecyclerView , asegúrese de tenerlo en cuenta al actualizar los datos de los adaptadores.

Ejemplo:

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

Editar: supongo que siempre puedes usar el método del adaptador getItemCount() para obtener el tamaño, en lugar de obtener el tamaño de la "lista de datos" y agregarlo. Su método getItemCount() ya debería tener en cuenta cualquier encabezado / pie de página / etc adicional que tenga en su lista.


Tuve un problema similar, y también esta solución me ha ayudado, después de haber agregado un nuevo elemento a mi RV:

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


Tuve un problema similar. Eliminar todas las vistas de RecyclerView me ayudó:

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


Use esto para actualizar un RecyclerView

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

`


Yo tuve el mismo problema. Volver a crear la nueva lista solucionó el problema perfectamente:

en clase de adaptador

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