You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

notifyDataSetChanged()执行顺序异常问题:为何nextPlayer()先于notifyDataSetChanged()生效?

问题分析与解决方案

这是一个典型的Android UI更新异步性导致的时序问题,我来帮你拆解一下原因和解决办法:

核心原因:notifyDataSetChanged()的异步特性

Android的UI操作是基于主线程消息队列驱动的,notifyDataSetChanged()并不会立即触发RecyclerView的视图绑定。它只是给主线程发送了一个"需要更新UI"的请求,这个请求会排队等待当前正在执行的代码(也就是你的executeBustConsequences()方法)完成后才会被处理。

而你的nextPlayer()是同步执行的——在notifyDataSetChanged()发送更新请求后,代码会立刻执行nextPlayer()修改playerIndex和currentDart的值。等到RecyclerView真正开始执行onBindViewHolder刷新视图时,这两个值已经被修改成切换玩家后的状态了,所以你在Adapter里看到的是getCurrentDart() == 1且getPlayerIndex() == 1。

另外还有一个可能的隐藏问题:如果你的Adapter在onBindViewHolder里不是从自身的数据源列表中读取状态,而是直接调用Activity的getCurrentDart()和getPlayerIndex()方法,那即使notifyDataSetChanged()先执行,后续nextPlayer()修改的实时状态也会被Adapter直接读取到,这也会导致显示不符合预期。

针对性解决方案

方案1:让nextPlayer()等待UI更新完成

利用RecyclerView.post()方法,把nextPlayer()的执行放到主线程消息队列的末尾,确保UI更新任务先完成,再切换玩家:

getAdapter().notifyDataSetChanged();
// 把切换玩家的操作放到UI更新之后执行
recyclerView.post(() -> nextPlayer());

方案2:重构Adapter的状态依赖(更推荐)

让Adapter的视图绑定完全依赖自身的数据源,而不是Activity的全局状态:

  1. 在你的玩家数据模型类中添加isCurrentPlayer、currentDartCount这类字段,把当前玩家、投掷次数的状态封装到数据源里;
  2. 在executeBustConsequences()更新数据源时,同步更新这些状态字段;
  3. Adapter在onBindViewHolder中直接从模型对象读取这些值,不再调用Activity的getCurrentDart()或getPlayerIndex()。

这样无论UI更新的时序如何,Adapter展示的都是数据源中保存的、你期望的状态,从根源上避免了时序问题。

额外检查点

你可以确认一下updateAverages()方法内部有没有隐藏的异步操作(比如用Handler.post()、View.post()修改状态),虽然你提到在notifyDataSetChanged()前状态是正确的,但排除这类潜在的干扰能让问题定位更准确。

内容的提问来源于stack exchange,提问作者Blaupunkt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 19:52:41