2017-03-28 20 views
3

私はAndroidアプリケーションを開発しています。これをプレイストアに公開した後、この問題に直面しました。例外java.lang.IndexOutOfBoundsException:不一致が検出されました。無効なビューホルダーアダプター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) 

私はこの問題について長い時間を検索し、多くのソリューションを適用するが、例外はまだ

を上げた私が塗布された溶液の一つは、カスタム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; 
    } 
} 

依存RecyclerViewでをロードmoreスワイプで更新する機能

I ロードRecyclerViewに詳しい項目をロードするために

をリフレッシュするために、よりとスワイプするためのWebサービスからデータを取得するためにバレーボールを使用して、バックバレーボール応答のコールの内側に私はArrayListに新しいアイテムを追加し、通知LOAの場合Adapter.UpdateItems

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

ため

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

コード:このようにアダプタdもっと私は以下を行います。 OnRefresh

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

LatestEntryためのコードは次のとおりです。

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

次の点に注意してください

  1. Recyclerviewバージョンは次のとおりです。recyclerview-V7:25.3.0
  2. 私が持っていますViewPagerの3つのRecylerView
  3. 各ViewPagerにはフラグメントが含まれ、フラグメントにはListFが含まれますRecylerViewとの競合。
  4. すべてのRecylcrViewに1つのアダプタがあります。

この問題を解決する方法はありますか?

+0

reccyleviewサポートライブラリのバージョンは何ですか? –

+0

私はこのバージョンを使用していますrecyclerview-v7:25.3.0 –

+0

FYI: 'onLayoutChildren()'はここでは問題ありません。スタックトレースはリストに表示されません。 –

答えて

0

RecyclerView$Recycler.validateViewHolderForOffsetPositionは有効なViewHolderアイテムが届かないと文句を言っていますが、これは11番目のアイテムのオフセット位置にあるようです。

アダプタにアイテムを追加するときにViewHolderを膨らませることを忘れてしまったと思われます。処理方法が間違っているように見えます。通常は、データ配列を更新してからアダプタに通知するだけです。 notifyDataChanged();アダプタにアイテムを直接追加すると、これらの通知が内部的にトリガされると考えられます。

swipeRefreshLayout.setRefreshing(false)は、ロード完了後にホイールアニメーションが消えるように、コールバックメソッド内で発生するはずです。

おそらくフレームワークがイベントをトリガーする順番を考えてみてください(したがって、フレームワークがすでに持っている機能を作成するということはしばしば問題です)。手がかり、その項目に有効なViewHolderが膨らんでいるのはなぜですか?

+0

私はあなたに提案を試みました**今は**読み込み中**データを一時リストに追加してからアダプターのリストを一度更新してから 'notifyItemRangeInserted'を呼び出しましたが、Google Playにアプリを公開した後でもう一度例外が表示されました。 –

+0

@ MohammedK.Abuhalibは、クラッシュ報告を見ていない間にしか推測できません。おそらくProGuardがあまりにも難読化している(そしておそらく、そのクラスの '-dontnote'または' -dontwarn'フラグを持っていて、未知のクラスについて不平を言っていない)...これらの設定ルールを削除する(またはコメントアウトする)ことは、私が取る最初のステップ。 'mapping.txt'をアップロードすることも有用です。 –

+0

私はProGuard難読化を使用しません。私は '-dontnote'または' -dontwarn'フラグを使用せず、proguard-rules.proファイルも空です。 –

0

私は同様の状況があります - viewpagersはリサイクルビューのアイテムです。アイテムを削除している間に、これらの「削除待ち」アイテムのアニメーションがいくつかありました。私が呼んでいたときに項目を削除し、アニメーションはまだ私が持って行動していた:

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

私は削除するアイテムを遅らせるためのハンドラを作成しました。この例外を回避するには。しかし!これは間違っています。アダプタRVのデータを変更した場合は、ハンドラやマルチスレッドにこれらの変更を通知しなくてもすぐにRVを変更する必要があります。 このようにして、更新が別々のスレッドを必要としないものに変更することを考えてください。私のために働いたnotifyItemRangeInserted(positionStart,itemCount);

を呼び出す前に

-1

コールnotifyItemRangeChanged(positionStart,itemCount)

関連する問題