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

Android应用RecyclerView适配器未绑定错误求助

解决RecyclerView "No adapter attached; skipping layout" 错误

核心问题分析

  1. RecyclerView布局时无适配器:适配器在异步协程中设置,RecyclerView首次布局时协程未完成,导致无适配器绑定触发错误。
  2. 初始selectedVehicle为空:onCreateView中初始化selectedVehicle时,vehicles列表还未从Room加载完成(loadVehiclesFromRoom是异步操作),后续协程无法正确获取车辆的加油数据,甚至可能创建不出适配器。
  3. Spinner数据加载后未触发RecyclerView更新:车辆列表加载完成后,未自动选中车辆并刷新RecyclerView数据。
  4. 新增数据后未刷新列表:保存新的加油记录后,RecyclerView未重新加载数据,无法显示新记录。

具体修复步骤

1. 给RecyclerView设置初始空适配器

在onCreateView中初始化RecyclerView后,立即设置空适配器,确保布局时始终有适配器绑定:

// 初始化RecyclerView
CargaRecyclerView = binding.recyclerView
val layoutManager = LinearLayoutManager(requireContext())
CargaRecyclerView.layoutManager = layoutManager
// 设置初始空适配器(根据CargaAdapter构造函数调整,允许空Vehicle或传临时对象)
val initialAdapter = CargaAdapter(requireContext(), emptyList(), selectedVehicle ?: Vehicle(0, "", "", "", 0.0))
CargaRecyclerView.adapter = initialAdapter

如果CargaAdapter不接受null的Vehicle,可以修改Adapter构造函数让Vehicle参数为Vehicle?,或者传一个默认空Vehicle对象。

2. 修复selectedVehicle的赋值逻辑

移除onCreateView中初始的selectedVehicle赋值,改为在Spinner选择事件中更新,且每次选择车辆时重新加载RecyclerView数据:

// 给Spinner设置选择监听
spinnerVehicles.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        selectedVehicle = vehicles[position]
        // 选择车辆后重新加载该车辆的加油记录
        loadCargasForSelectedVehicle()
    }

    override fun onNothingSelected(parent: AdapterView<*>?) {
        selectedVehicle = null
        // 未选择车辆时清空RecyclerView
        (CargaRecyclerView.adapter as? CargaAdapter)?.updateData(emptyList(), null)
    }
}

3. 替换GlobalScope避免内存泄漏

用viewLifecycleOwner.lifecycleScope替换GlobalScope,确保协程在Fragment销毁时自动取消:

// 顶部添加import
import androidx.lifecycle.lifecycleScope

// 所有协程调用替换为:
lifecycleScope.launch(Dispatchers.IO) {
    // 异步逻辑代码
}

4. 封装加载加油记录的函数

创建单独函数加载选中车辆的加油记录并更新适配器:

private fun loadCargasForSelectedVehicle() {
    selectedVehicle?.let { vehicle ->
        lifecycleScope.launch(Dispatchers.IO) {
            val listaDeCargas = appDatabaseCarga.cargaCombustibleDao().obtenerCargasPorVehiculo(vehicle.id.toLong())
            withContext(Dispatchers.Main) {
                val adapter = CargaRecyclerView.adapter as? CargaAdapter
                adapter?.updateData(listaDeCargas, vehicle)
                // 若没有updateData方法,可直接替换适配器:
                // CargaRecyclerView.adapter = CargaAdapter(requireContext(), listaDeCargas, vehicle)
            }
        }
    }
}

建议给CargaAdapter添加updateData方法,避免频繁创建新适配器:

// 在CargaAdapter中添加
fun updateData(newData: List<CargaCombustible>, vehicle: Vehicle?) {
    this.cargas = newData
    this.selectedVehicle = vehicle
    notifyDataSetChanged()
}

5. 车辆加载完成后自动选中第一个车辆

修改loadVehiclesFromRoom,加载完成后自动选中第一个车辆(如果有):

private fun loadVehiclesFromRoom() {
    vehicles.clear()
    lifecycleScope.launch(Dispatchers.IO) {
        val vehicleEntities = appDatabase.vehicleDao().obtenerVehiculos()
        for (entity in vehicleEntities) {
            val vehicle = Vehicle(entity.id, entity.marca, entity.tipo, entity.modelo, entity.kilometros)
            vehicles.add(vehicle)
        }
        withContext(Dispatchers.Main) {
            spinnerAdapter.clear()
            spinnerAdapter.addAll(vehicles.map { "${it.brand} ${it.model}" })
            spinnerAdapter.notifyDataSetChanged()
            // 自动选中第一个车辆
            if (vehicles.isNotEmpty()) {
                spinnerVehicles.setSelection(0)
            }
        }
    }
}

6. 保存新记录后刷新RecyclerView

修改saveCargaCombustibleToRoom,保存完成后重新加载数据,同时修复车辆ID关联问题:

private fun saveCargaCombustibleToRoom(cargaCombustible: CargaCombustible) {
    lifecycleScope.launch(Dispatchers.IO) {
        val ultimoId: Long? = appDatabaseCarga.cargaCombustibleDao().obtenerUltimoIdCarga()
        val nuevoId: Long = (ultimoId ?: 0) + 1
        cargaCombustible.idCarga = nuevoId
        // 修复:设置正确的车辆ID,而非固定0
        cargaCombustible.idVehiculo = selectedVehicle?.id?.toLong() ?: 0
        appDatabaseCarga.cargaCombustibleDao().insertarCarga(cargaCombustible)
        // 回到主线程刷新列表并清空输入框
        withContext(Dispatchers.Main) {
            loadCargasForSelectedVehicle()
            binding.editTextLitros.text.clear()
            binding.editTextPrecio.text.clear()
        }
    }
}

额外建议

  • 将数据加载逻辑移到onViewCreated中,避免onCreateView中执行过多异步操作。
  • 使用Room的Flow或LiveData观察数据变化,实现自动更新RecyclerView,减少手动刷新代码:
// 观察车辆列表变化
appDatabase.vehicleDao().obtenerVehiculosFlow().asLiveData().observe(viewLifecycleOwner) { entities ->
    // 更新vehicles列表和Spinner
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 04:38:12