Kotlin回调函数内修改变量后外部仍为旧值问题排查
问题根因
你遇到的是异步回调执行时序问题,所有Firestore的get()数据库请求都是异步IO操作,不会阻塞当前线程执行:
- 调用
getItemViewType时,执行到rowManager.changeViewType会触发后台数据库查询,主线程不会等待查询结果返回,会直接继续执行后续的日志打印和return rowViewType逻辑,此时rowViewType还是初始赋值的0。 - 等到后台查询完成、回调接口
rowViewType被触发时,getItemViewType方法早就执行结束返回了,你在回调中给rowViewType赋的新值,完全无法影响已经返回的结果,这就是你观察到回调内部值更新、外层还是旧值的原因。
另外注意:getItemViewType是Android列表系统提供的同步回调方法,要求你立即返回类型值,绝对不能在这个方法内做异步查询等待操作,会严重拖慢列表滑动性能,甚至触发ANR异常。
解决方案
核心思路是提前加载好所有搜索结果用户的展示类型,存储到用户模型中,列表回调直接读取预存值即可,具体改造步骤:
- 给
UserModel新增可空viewType字段,用来存储该条目的展示类型 - 在拿到搜索接口返回的用户列表后,批量触发所有用户的好友/请求状态查询,查询完成后把类型赋值给对应用户的
viewType字段,全部加载完成后刷新列表 getItemViewType方法内直接读取UserModel中预存的viewType返回即可
改造后代码示例
优化后的getItemViewType
override fun getItemViewType(position: Int): Int { val user = userList[position] // 未加载完成时可以先返回默认占位样式,加载完成后自动刷新 return user.viewType ?: 0 }
搜索结果处理逻辑
// 拿到搜索返回的用户列表后,批量加载展示类型 fun loadSearchResultViewTypes(userList: List<UserModel>) { val finishCounter = AtomicInteger(0) userList.forEach { user -> rowManager.changeViewType(user, object : RowListener { override fun rowViewType(viewTypeNumber: Int) { user.viewType = viewTypeNumber // 所有用户类型加载完成后刷新列表 if (finishCounter.incrementAndGet() == userList.size) { yourAdapter.notifyDataSetChanged() } } }) } }
可选优化
如果搜索结果数量较多,可以做懒加载:列表滑动到对应位置时再触发该条目标题的类型查询,查询完成后调用notifyItemChanged(position)单独刷新单条即可,不需要等待所有结果加载完成再刷新。
内容的提问来源于stack exchange,提问作者fatihkk0
相关产品推荐
相关产品推荐

