Skip to main content
 首页 » 编程设计

android-recyclerview之Recycler View : Inconsistency detected. View 支架适配器positionViewHolder无效

2024年04月12日18findumars

回收器 View 不一致检测到错误,在快速滚动或在加载更多项目时滚动时出现。

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) 

适配器

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

事件

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

请您参考如下方法:

put this line along with setting recyclerView. issue was fixed by setting ItemAnimator to null for RecyclerView.

在 Kotlin

    recyclerView.layoutManager = LinearLayoutManager(this) 
    recyclerView.itemAnimator = null 

在java中

    recyclerView.setItemAnimator(null);