2017-03-28 2 views
3

Ich entwickle Android-Anwendung und nachdem es auf Play Store veröffentlicht, ich konfrontiert dieses Problem viele Zeit.Ausnahme java.lang.IndexOutOfBoundsException: Inkonsistenz festgestellt. Invalid View Halter Adapter PositionViewHolder

Exception java.lang.IndexOutOfBoundsException: Inconsistency detected.Invalid view holder adapter positionViewHolder{2f9d83c position=11 id=-1, oldPos=-1, pLpos:-1 no parent} 
android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition (RecyclerView.java:5297) 
android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline (RecyclerView.java:5479) 
android.support.v7.widget.GapWorker.prefetchPositionWithDeadline (GapWorker.java:282) 
android.support.v7.widget.GapWorker.flushTaskWithDeadline (GapWorker.java:336) 
android.support.v7.widget.GapWorker.flushTasksWithDeadline (GapWorker.java:349) 
android.support.v7.widget.GapWorker.prefetch (GapWorker.java:356) 
android.support.v7.widget.GapWorker.run (GapWorker.java:387) 
android.os.Handler.handleCallback (Handler.java:815) 
android.os.Handler.dispatchMessage (Handler.java:104) 
android.os.Looper.loop (Looper.java:207) 
android.app.ActivityThread.main (ActivityThread.java:5737) 
java.lang.reflect.Method.invoke (Method.java) 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:789) 
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:679) 

ich für lange Zeit über dieses Problem gesucht und viel Lösung anzuwenden, sondern die Ausnahme ausgelöst noch

Eine Lösung, die ich angelegt machen Benutzerdefinierte LinearLayoutManager:

public class WrapContentLinearLayoutManager extends LinearLayoutManager { 

    public WrapContentLinearLayoutManager(Context context) { 
     super(context); 
    } 

    //... constructor 
    @Override 
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 
     try { 
      super.onLayoutChildren(recycler, state); 
      setAutoMeasureEnabled(false); 
     } catch (IndexOutOfBoundsException e) { 
      Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens"); 
     } 
    } 

    public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 
     super(context, orientation, reverseLayout); 
     setAutoMeasureEnabled(false); 
    } 

    public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 
     setAutoMeasureEnabled(false); 
    } 

    @Override 
    public boolean supportsPredictiveItemAnimations() { 
     return false; 
    } 
} 

in meiner Anwendung hängt auf RecyclerView mit Laden Sie mehr und Wischen zum Aktualisieren Funktionen

ich Volley mit Arraylist zu bekommen Daten aus Web-Service für laden mehr und Swipe zu aktualisieren

laden Weitere Artikel in RecyclerView, innerhalb der Rückruf von Volley Antwort anhängen ich die neuen Angebote im zu und benachrichtigen der Adapter wie folgt aus:

final int positionStart = list.size() - 1; 
    final int itemCount = response.length(); 
    for (int i=0;i<response.length();i++) 
    { 
     try 
     { 
      obj = response.getJSONObject(i); 
      list.add(new ItemEntry(obj.getInt("Id"),obj.getString("Title").trim()obj.getBoolean("isFavorite")); 
     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
     if(index == 0) 
     { 
      // for first Initialize for adapter 
      adapter = new MyAdapter(latestEntryList,getActivity()); 
      adapter.setOnItemClickCallBack(mainFragment); 
      recyclerView.setAdapter(adapter); 
     } 
     else 
     { 
      // for load more items 
      recyclerView.post(new Runnable() 
      { 
       @Override 
       public void run() 
       { 
        adapter.updateItems(positionStart,itemCount); 
       } 
      }); 
     } 
    } 

der Kodex für Adapter.UpdateItems

public void updateItems(int positionStart,int itemCount) { 
     itemsCount = getItemCount(); 
     this.notifyItemRangeInserted(positionStart,itemCount); 
    } 

Bei loa d Mehr mache ich folgendes; in OnRefresh

public void onRefresh() { 
     listFragment.LatestEntry(0,false); 
// 0 the index and False isAppend to list of not 
    } 

Der Code für LatestEntry ist:

private void LatestEntry(final int index, final boolean isAppend) 
     { 
     String customerId = "123"; 
     String uri = String.format(BASE_URL+"/api/Entry/LatestEntry?customerId=%s&index=%s",customerId,index); 

      JsonArrayRequest LatestEntryJsonArrayRequest = new JsonArrayRequest(Request.Method.GET, uri, 
       null, new Response.Listener<JSONArray>() { 
       @Override 
       public void onResponse(JSONArray response) 
        { 
         JSONObject obj = new JSONObject(); 
         if(response.length() > 0 && !isAppend) 
         { 
          int startPosition = 0; 
          int preSize; 

          if(adapter != null) 
           preSize = adapter.entries.size(); 
          else 
           preSize = 0; 
          if(preSize > 0 && EntryList.size() > 0) { 
           EntryList.clear(); 
           adapter.entries.clear(); 
           adapter.notifyItemRangeRemoved(startPosition, preSize); 
          } 
         } 

         final int positionStart = EntryList.size() - 1; 
         final int itemCount = response.length(); 
         for (int i=0;i<response.length();i++) 
         { 
          try { 
           obj = response.getJSONObject(i); 
           list.add(new ItemEntry 
           (obj.getInt("Id"),obj.getString("Title").trim() 
            obj.getBoolean("isFavorite")); 

          } catch (JSONException e) { 
           e.printStackTrace(); 
          } 
         } 

         if(index == 0) 
         { // for first Initialize for adapter 
          adapter = new MyAdapter(latestEntryList,getActivity()); 
          adapter.setOnItemClickCallBack(mainFragment); 
          recyclerView.setAdapter(adapter); 
         } 
         else 
         { 
          // for load more items 
          recyclerView.post(new Runnable() 
          { 
           @Override 
           public void run() { 
            adapter.updateItems(positionStart,itemCount); 
           } 
          }); 
         } 
        } 
        setListShownNoAnimation(true); 
        if(mainFragment.swipeRefreshLayout.isRefreshing()) 
         mainFragment.swipeRefreshLayout.setRefreshing(false); 
       } 
      }, new Response.ErrorListener() { 
       @Override 
       public void onErrorResponse(VolleyError error) { 
        Toast.makeText(MyApplication.getAppContext(),error.getMessage(),Toast.LENGTH_LONG); 
       } 
      } 
      ); 

      LatestEntryJsonArrayRequest.setTag("LatestEntry"); 
      KidsSingleton.getInstance().addToRequestQueue(LatestEntryJsonArrayRequest); 
     } 

Bitte beachten Sie folgendes:

  1. Die Recyclerview Version ist: recyclerview-v7: 25.3.0
  2. Ich habe Three RecylerView in ViewPager
  3. Jeder ViewPager enthält Fragment und das Fragment enthält ListF ragment mit RecylerView.
  4. Es gibt einen Adapter für alle RecylcrViews.

Kann jemand helfen, dieses Problem zu überwinden?

+0

Was ist die Version Ihrer Recyleview-Support-Bibliothek? –

+0

Ich benutze diese Version recyclerview-v7: 25.3.0 –

+0

FYI: 'onLayoutChildren()' ist hier kein Problem - Ihr StackTrace zeigt es nicht in der Liste. –

Antwort

0

RecyclerView$Recycler.validateViewHolderForOffsetPosition beschwert sich darüber, keine gültigen ViewHolder Artikel zu erhalten, während es an der Offset-Position des 11. Artikels zu sein scheint.

würde annehmen, dass Sie möglicherweise vergessen haben, die ViewHolder aufzublasen, wenn Sie mehr Elemente zum Adapter hinzufügen ... die Art der Verarbeitung erscheint falsch; während gewöhnlich, muss man nur das Datenfeld aktualisieren und dann den Adapter mit z. notifyDataChanged(); Denken Sie beim direkten Hinzufügen von Elementen zum Adapter daran, dass diese Benachrichtigungen intern ausgelöst werden.

Die swipeRefreshLayout.setRefreshing(false) sollte wahrscheinlich innerhalb einer Callback-Methode passieren, so dass die Radanimation verschwindet, wenn das Laden abgeschlossen ist.

vielleicht überprüfen Sie diese example, um eine Idee zu bekommen, in welcher Reihenfolge das Framework die Ereignisse auslöst (daher ist es oft das Problem, dass man Funktionalität schafft, die das Framework schon mitbringt) ... stepping könnte auch ein Hinweis, warum gibt es keine gültige ViewHolder wird für diesen Artikel aufgeblasen.

+0

Ich habe versucht, Vorschlag, und jetzt auf ** Laden mehr ** Ich Hinzufügen von Daten zu Temp-Liste dann Updates Adapter-Liste einmal und dann namens "notifyItemRangeInserted", aber nachdem ich die App zu Google Play veröffentlichte die Ausnahme erschien wieder. –

+0

@ MohammedK.Abuhalib kann nur raten, ohne die Unfallmeldung zu sehen; Die Chancen stehen gut, dass ProGuard ein wenig zu sehr verschleiert (und wahrscheinlich sogar "-dontnote" oder "-dontwarn" -Flags für diese Klasse hat und sich daher nicht über unbekannte Klassen beschwert) ... das Entfernen (oder Auskommentieren) dieser Konfigurationsregeln wäre der erste Schritt, den ich machen würde. Das Hochladen von 'mapping.txt' ist ebenfalls nützlich. –

+0

Ich verwende keine ProGuard-Verschleierungen, ich benutze keine '-dontnote'- oder '-dontwarn'-Flags und auch die proguard-rules.pro-Datei ist leer. –

0

Ich habe ähnliche Situation - Viewpager als Elemente der Recycler anzeigen. Beim Hinzufügen von Elementen zum Entfernen von Objekten gab es eine Animation für diese Elemente, die darauf warten, entfernt zu werden. Also, wenn ich Artikel Aufruf entfernen, und Animation noch benahm ich habe:

IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling 

diese Ausnahme zu vermeiden ich einen Handler erstellt haben Entfernen von Elementen zu verzögern. ABER! Das ist falsch. Wenn Sie die Daten des Adapters geändert haben, sollte RV sofort ohne einen Handler oder Multithreading über diese Änderungen benachrichtigt werden. Denken Sie also darüber nach, diesen Weg in etwas zu ändern, bei dem Updates keine separaten Threads benötigen.

-1

Anruf notifyItemRangeChanged(positionStart,itemCount)

Vor notifyItemRangeInserted(positionStart,itemCount);

Arbeitete für mich so zu nennen.

Verwandte Themen