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

Async配合RecyclerView加载数据时如何边加载边逐条追加显示列表

问题根因定位
  • 回调线程问题:首先排查deviceWearableService.getBuilding的成功回调是否执行在子线程。Android要求所有UI更新操作必须在主线程执行,如果你在子线程调用notifyItemInserted,系统不会立刻触发RecyclerView重绘,会把所有更新事件攒到主线程下一次批量处理,就会出现所有数据加载完成后统一渲染的现象。
  • 初始化顺序问题:你的代码先触发所有fetchBuildingAddress请求,之后才给RecyclerView设置adapter和layoutManager。如果部分请求返回速度快于RecyclerView初始化流程,前几个返回数据的插入通知不会被还没绑定的RecyclerView接收,等RecyclerView初始化完成后才会一次性处理所有攒下的插入事件,也会导致批量渲染。
修复方案

1. 先完成RecyclerView初始化再发起请求

调整onCreateView里的代码顺序,先给RecyclerView设置好布局管理器和适配器,再发起批量请求:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val view = inflater.inflate(R.layout.fragment_lock_list, container, false)
    val recyclerView = view.findViewById<RecyclerView>(R.id.list)

    // 先初始化RecyclerView
    with(recyclerView) {
        layoutManager = LinearLayoutManager(context)
        adapter = deviceRecyclerViewAdapter
    }

    // 再发起请求
    for(device in devices) {
        fetchBuildingAddress(device)
    }

    return view
}

2. 强制UI更新操作切到主线程执行

在插入数据前先判断当前线程,确保notifyItemInserted在主线程调用,修改fetchBuildingAddress的回调逻辑:

private fun fetchBuildingAddress(device: Device) {
    deviceWearableService.getBuilding(device.buildingId) {
        when(it) {
            is DeviceWearableServiceImpl.State.Success -> {
                val buildingName = it.resources.buildingAddress.address1
                val deviceBuilding = DeviceBuillding(device, buildingName)
                // 切主线程执行插入更新
                Handler(Looper.getMainLooper()).post {
                    deviceRecyclerViewAdapter.insertDevice(deviceBuilding)
                }
            }
            else -> {
                // TODO: ERROR STATE
            }
        }
    }
}

3. 可选优化方案

如果你的请求可以控制并发,也可以改用串行请求的方式,加载完一条再发起下一条请求,更贴合逐条加载的交互预期:

// 把请求列表转成迭代器逐次调用
private lateinit var deviceIterator: Iterator<Device>

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val view = inflater.inflate(R.layout.fragment_lock_list, container, false)
    val recyclerView = view.findViewById<RecyclerView>(R.id.list)

    with(recyclerView) {
        layoutManager = LinearLayoutManager(context)
        adapter = deviceRecyclerViewAdapter
    }

    deviceIterator = devices.iterator()
    fetchNextDevice()

    return view
}

private fun fetchNextDevice() {
    if (deviceIterator.hasNext()) {
        val device = deviceIterator.next()
        deviceWearableService.getBuilding(device.buildingId) {
            when(it) {
                is DeviceWearableServiceImpl.State.Success -> {
                    val buildingName = it.resources.buildingAddress.address1
                    val deviceBuilding = DeviceBuillding(device, buildingName)
                    Handler(Looper.getMainLooper()).post {
                        deviceRecyclerViewAdapter.insertDevice(deviceBuilding)
                    }
                }
            }
            // 不管成功失败都加载下一条
            fetchNextDevice()
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 18:18:01