RecyclerView滚动至指定位置后执行点击导致崩溃问题求助
解决RecyclerView滚动后立刻点击最后一项崩溃的问题
这个坑我之前踩过!你遇到的问题本质是RecyclerView的滚动操作是异步执行的——当你调用scrollToPosition()后,系统并不会立刻把目标Item加载到屏幕上,这时候用getChildAt(latestPostIndex)去拿View,大概率会拿到null,直接调用performClick()自然就崩溃了。
下面给你两种靠谱的解决方案:
方案一:监听滚动状态,停止后再执行点击
利用RecyclerView的滚动监听,等滚动完全停止(进入IDLE状态)后,再检查目标Item是否已经可见,然后执行点击:
// 先获取目标索引 int latestPostIndex = reactionsListAdapter.getItemCount() - 1; // 添加滚动监听 rvReactionsList.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 当滚动停止时 if (newState == RecyclerView.SCROLL_STATE_IDLE) { LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (layoutManager == null) return; // 确认最后可见的Item就是我们要点击的目标 if (layoutManager.findLastVisibleItemPosition() == latestPostIndex) { // 通过布局管理器获取目标View(比getChildAt更可靠) View targetView = layoutManager.findViewByPosition(latestPostIndex); if (targetView != null) { targetView.performClick(); // 记得移除监听,避免后续滚动重复触发 recyclerView.removeOnScrollListener(this); } } } } }); // 触发滚动 rvReactionsList.scrollToPosition(latestPostIndex);
这里要注意:getChildAt()的参数是屏幕上可见子View的索引,不是Adapter中的Item位置,所以用layoutManager.findViewByPosition()来获取对应位置的View才是正确的做法。
方案二:监听Item的加载状态,加载完成后点击
通过Adapter的DataObserver,监听Item是否被加载到窗口,一旦目标Item可用就执行点击:
int latestPostIndex = reactionsListAdapter.getItemCount() - 1; // 注册数据观察者 RecyclerView.AdapterDataObserver observer = new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); checkAndClickTargetItem(); } }; reactionsListAdapter.registerAdapterDataObserver(observer); // 检查并点击目标Item的方法 private void checkAndClickTargetItem() { LinearLayoutManager layoutManager = (LinearLayoutManager) rvReactionsList.getLayoutManager(); if (layoutManager == null) return; View targetView = layoutManager.findViewByPosition(latestPostIndex); if (targetView != null) { targetView.performClick(); // 注销观察者,避免重复执行 reactionsListAdapter.unregisterAdapterDataObserver(observer); } } // 先触发滚动 rvReactionsList.scrollToPosition(latestPostIndex); // 立刻检查一次(如果Item已经在屏幕上就直接点击) checkAndClickTargetItem();
额外注意事项
- 不管用哪种方案,都要记得移除监听/注销观察者,否则会导致内存泄漏或者重复执行点击操作
- 如果你的RecyclerView用的是
GridLayoutManager,只需要把代码里的LinearLayoutManager换成GridLayoutManager即可,findLastVisibleItemPosition()和findViewByPosition()是LayoutManager的通用方法 - 所有涉及到LayoutManager和View的地方都要做null判断,避免空指针异常
内容的提问来源于stack exchange,提问作者Chandan Pednekar
相关产品推荐
相关产品推荐

