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

无法将LiveData数据显示到RecyclerView问题求助

问题描述

我有一个EditText和一个Button,点击Button时EditText的内容会被插入到与LiveData关联的列表中。我希望将列表中的数据显示在RecyclerView中,但目前没有任何数据显示。我怀疑Observer未被调用(它呈现灰色,与未使用的变量/函数状态相同),也可能存在其他问题。

Activity类代码

class MainActivity : AppCompatActivity(), NoteAdapter.OnItemClicked {

    private lateinit var recyclerView: RecyclerView
    private lateinit var btnAdd: Button
    private lateinit var etNote: EditText
    lateinit var viewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        recyclerView = findViewById(R.id.recyclerView)
        btnAdd = findViewById(R.id.btn_add)
        etNote = findViewById(R.id.et_note)

        val mAdapter = NoteAdapter(this, this)

        recyclerView.apply {
            adapter = mAdapter
            layoutManager = LinearLayoutManager(this@MainActivity)
        }

        viewModel = ViewModelProvider(this,
            ViewModelProvider.AndroidViewModelFactory.getInstance(application))[MyViewModel::class.java]

        viewModel.allNotes.observe(this, Observer {
            it?.let {
                mAdapter.updateList(it)
            }
        })

        btnAdd.setOnClickListener {
            addNote()
        }
    }

    override fun onClick(note: Notes) {
        viewModel.delete(note)
    }

    private fun addNote(){
        val note: String = etNote.text.toString()

        if(note.isNotBlank()) {
            viewModel.insert(Notes(note))
            Toast.makeText(this, "$note inserted", Toast.LENGTH_SHORT).show()
        }
    }
}

Adapter代码

class NoteAdapter(private val context: Context, private val clickListener: OnItemClicked) : RecyclerView.Adapter<NoteAdapter.MyViewHolder>() {

    private val allNotes = mutableListOf<Notes>()

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvNoteItem: TextView = itemView.findViewById(R.id.tv_note)
        val ivDelete: ImageView = itemView.findViewById(R.id.iv_delete)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.note_item, parent, false)
        val viewHolder = MyViewHolder(view)

        viewHolder.ivDelete.setOnClickListener{
            clickListener.onClick(allNotes[viewHolder.adapterPosition])
        }

        return viewHolder
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val currentNote = allNotes[position]
        holder.apply {
            tvNoteItem.text = currentNote.note
        }
    }

    override fun getItemCount() = allNotes.size

    interface OnItemClicked{
        fun onClick(note: Notes)
    }

    fun updateList(newList: List<Notes>){
        allNotes.clear()
        allNotes.addAll(newList)
        notifyDataSetChanged()
    }
}

实体类代码

@Entity(tableName = "notes_table")
data class Notes(val note: String) {
    @PrimaryKey(autoGenerate = true)
    var id = 0
}

Dao代码

@Dao
interface NotesDao {

    @Insert
    suspend fun insertNote(note: Notes){  //Suspended means it will run it background thread

    }

    @Delete
    suspend fun deleteNotes(note: Notes){

    }

    @Query("Select * from notes_table order by id")
    fun getAllNotes(): LiveData<List<Notes>>
}

Database代码

@Database(entities = arrayOf(Notes::class), version = 1, exportSchema = false)
abstract class NoteDatabase : RoomDatabase() {

    abstract fun noteDao() : NotesDao

    companion object{

        // Singleton prevents multiple instances of database opening at the
        // same time.
        @Volatile
        private var INSTANCE: NoteDatabase? = null

        fun getDatabase(context: Context): NoteDatabase {
            // if the INSTANCE is not null, then return it,
            // if it is, then create the database
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    NoteDatabase::class.java,
                    "notes_table"
                ).build()
                INSTANCE = instance
                // return instance
                instance
            }
        }
    }
}

ViewModel代码

class MyViewModel(application: Application) : AndroidViewModel(application) {

    private val repository: NotesRepository
    val allNotes : LiveData<List<Notes>>

    init {
        val dao = NoteDatabase.getDatabase(application).noteDao()
        repository = NotesRepository(dao)
        allNotes = repository.noteList
    }

    fun delete(note: Notes) = viewModelScope.launch(Dispatchers.IO) {
        repository.delete(note)
    }

    fun insert(note: Notes) = viewModelScope.launch(Dispatchers.IO) {
        repository.insert(note)
    }
}

Repository代码

class NotesRepository(private val dao: NotesDao) {

    val noteList = dao.getAllNotes()

    suspend fun insert(note: Notes){
        dao.insertNote(note)
    }

    suspend fun delete(note: Notes){
        dao.deleteNotes(note)
    }
}

问题排查与修复方案

核心问题:Dao层方法空实现

你的NotesDao中insertNote和deleteNotes方法是空的!Room的@Insert、@Delete注解方法不需要手动写空实现,Room会自动生成对应的数据库操作代码。空实现导致数据根本没插入到数据库,LiveData自然不会收到更新通知,RecyclerView也就没有数据可显示。

修正后的Dao代码

@Dao
interface NotesDao {

    @Insert
    suspend fun insert(note: Notes)

    @Delete
    suspend fun delete(note: Notes)

    @Query("Select * from notes_table order by id")
    fun getAllNotes(): LiveData<List<Notes>>
}

其他优化建议

  1. 简化Observer写法:用Lambda表达式替代显式的Observer类,代码更简洁:
viewModel.allNotes.observe(this) { notes ->
    mAdapter.updateList(notes)
}
  1. 实体类主键优化:将id改为val,保持不可变性(Room会自动填充自增主键):
@Entity(tableName = "notes_table")
data class Notes(val note: String) {
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0
}
  1. 添加日志调试:在Observer中加入日志,确认LiveData是否收到更新:
viewModel.allNotes.observe(this) { notes ->
    Log.d("MainActivity", "收到笔记更新,数量:${notes.size}")
    mAdapter.updateList(notes)
}
  1. 校验布局ID:确保note_item布局中的tv_note和iv_delete与Adapter中findViewById的ID完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 19:00:59