2016-02-26 9 views
33

Recycler Ansicht Inkonsistenz Fehler erkannt, kommt während schnelle Scrollen oder Scrollen während mehr Einzelteile geladen ..Recycler View: Inkonsistenz festgestellt. Ungültige Ansicht Halteradapter positionViewHolder

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) 

Adapter

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); 
     } 
    } 
} 

Aktivität

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; 
    } 
} 
+0

Ich habe den gleichen Fehler kommt, weil ich endlose Recycler verwenden, wie meine Daten an die letzte Position erhalten es nicht die Anzahl der Elemente erhalten, wenn Sie es 27 Artikel Anzahl in jeder Rolle zuletzt Sie können sein bekomme nicht 27 Items, so dass es dann darauf folgt, wie ich bekomme, was das Problem gerade Logik erzeugt, wenn ich mod (%) list.size() nach item bekomme, wenn es gleich 0 ist, benutze nur notifyItemrangeInserted ansonsten notifyDataSetChanged (); –

+0

Gibt es eine Möglichkeit, dies zu reproduzieren? Ich erhalte diesen Absturz in meiner Produktions-App, kann ihn aber nicht lokal reproduzieren. – Ezio

Antwort

23

I t sieht ähnlich aus wie bei bekannten android bug

Es ziemlich hässlich sind, aber die Arbeit Ansatz

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)); 

Für mich ist es ohne Nebenwirkung funktioniert.

+0

Die App stürzt nach der Verwendung nicht ab, aber der Fehler ist immer noch vorhanden. Was ist der genaue Grund für diesen Fehler? –

+0

Dinge funktionieren .. aber könnten Sie den Grund des Absturzes erklären? –

+3

das ist eine wirklich schlechte Idee, die Ausnahme kappt und zum Schweigen bringen ... https://issuetracker.google.com/issues/37030377#comment9 @Angad Tiwari –

2

ich similiar Problem hatte, und auch diese Lösung hat mir geholfen, nachdem ich neues Element in mein RV hinzugefügt habe:

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

Dieses Problem ist ein Know Fehler von Recycling-Ansicht ist .Der beste Lösung

die Liste löschen, jedes Mal vor dem Refresh-Recycling-Ansicht

Für fix dieses Problem notifyDataSetChanged einfach anrufen() mit leerer Liste vor recycle Ansicht zu aktualisieren.

Zum Beispiel

//Method for refresh recycle view 

if (!yourList.isEmpty()) 

yourList.clear(); //The list for update recycle view 

adapter.notifyDataSetChanged(); 
+0

Ich falle dieses Problem recyclerview LoadMore Artikel –

+0

@AhamadullahSaikat hast du die Antwort bekommen? –

+0

Ja. Die erste Antwort dieser Frage ist für mich gearbeitet .. –

1

verwenden ein RecyclerView aufzufrischen

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 

`

0

ich dieses Problem hatte, als schnell durch meine endlos/Paging RecyclerView scrollen. Die Wurzel meines Problems kam von der Tatsache, dass ich ein "Header" -Element am Anfang der Liste hatte, dieses Header-Element war kein Teil der Datenquelle, es wurde nur am Anfang der adapter Liste eingefügt. Also, wenn schnell Scrollen und Hinzufügen neuer Seiten von Artikeln zu der RecyclerViewAdapter und Benachrichtigen Sie die adapter, dass neue Daten eingefügt wurden, habe ich nicht berücksichtigt, die zusätzliche Kopfzeile Element, wodurch die Größe der Adapterliste falsch ... und verursacht Diese Ausnahme ...

Kurz gesagt, wenn Sie eine Kopf-/Fußzeile in unserem RecyclerView Adapter verwenden, stellen Sie sicher, dass Sie dies beim Aktualisieren der Adapterdaten berücksichtigen.

Beispiel:

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()); 
} 

Edit: Ich denke, man könnte immer nur die Methode Adapter verwendet getItemCount() die Größe zu erhalten, anstatt die Größe aus der „Datenliste“ erhalten und das Hinzufügen zu es. Ihre getItemCount() Methode sollte bereits alle zusätzlichen Kopfzeilen/Fußzeilen/etc berücksichtigen, die Sie in Ihrer Liste haben.

Verwandte Themen