我有一个简单的RecyclerView,其中CardView为列表项。从Firebase Realtime数据库检索的列表中的每一项都存储到noteList中。 Firebase SDK为onChildAdded,onChildChanged和其他几个提供回调。现在,我已经设计了用于回收站 View 的适配器,以容纳ArrayList。每当实时数据库中的数据更改时,我都会使用回调向noteList添加或删除项目。每当特定项目的值更改时,就会调用onChildChanged方法。我想将此更改反射(reflect)在noteList中,并通知适配器。
当然,我们可以天真地搜索列表中与已更改元素的键匹配的每个元素,并对其进行更新。但是,能否以更好/更有效的方式做到这一点?

class NoteListAdapter(var data: MutableList<Note>, val onItemClick: (Note) -> Unit) : RecyclerView.Adapter<NoteListAdapter.ViewHolder>() {
    override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
        holder!!.bindNoteItem(data[position])
    }

    override fun getItemCount(): Int = data.size

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent?.context)
                .inflate(R.layout.card_note, parent, false)
        return ViewHolder(v, onItemClick)
    }

    class ViewHolder(v: View, val onItemClick: (Note) -> Unit): RecyclerView.ViewHolder(v) {
        fun bindNoteItem(note: Note) {
            ...
        }
    }
}

HomeActivity.kt
class HomeActivity : AppCompatActivity() {
    lateinit var mDb: DatabaseReference
    val noteList: MutableList<Note> = ArrayList()
    lateinit var adapter: NoteListAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        addNoteFAB.setOnClickListener { addNote() }
        mDb = FirebaseDatabase.getInstance().reference

        adapter = NoteListAdapter(noteList, this::editNote)
        noteListRecycler.layoutManager = LinearLayoutManager(this)
        noteListRecycler.adapter = adapter

        loadNotes()
    }

    fun addNote() {
        val intent = Intent(this, EditNoteActivity::class.java)
        intent.putExtra(EditNoteActivity.EXTRA_NOTE, Note())
        startActivity(intent)
    }

    fun loadNotes() {
        val path = "users/" + FirebaseAuth.getInstance().currentUser?.uid + "/notes"
        mDb.child(path ).addChildListener({
// onChildAdded
            dataSnapshot, prevChildName ->
            val note = dataSnapshot?.getValue(Note::class.java)!!
            note.id = dataSnapshot.key
            noteList += note
            adapter.notifyDataSetChanged()
        }, {
// onChildRemoved
            dataSnapshot ->
            noteList.remove(dataSnapshot?.getValue(Note::class.java))
            adapter.notifyDataSetChanged()
        }, {
// onChildChanged, TODO: update the change in elements value in noteList
            dataSnapshot, s ->

        })

    }

    fun editNote(note: Note) {
        val i = Intent(this, EditNoteActivity::class.java)
        i.putExtra(EditNoteActivity.EXTRA_NOTE, note)
        startActivity(i)
    }
}

PS:addChildListener是扩展功能。 (检查代码中的注释以获取回调的名称)

由于dataSnapshot只能告诉我们已更改的键和值(据我从文档中了解到的),如何在不知道已更改元素的索引的情况下如何更新noteList?还是真的有获取索引的方法?

最佳答案

到目前为止,我建议您使用FirebaseUI,它是专门为您的用例而构建的。

但是,如果您真的想独奏,那么不行,获取已更新子项索引的唯一方法是在现有数据中找到它。这是FirebaseUI内部的示例:

private int getIndexForKey(String key) {
    int index = 0;
    for (DataSnapshot snapshot : mSnapshots) {
        if (snapshot.getKey().equals(key)) {
            return index;
        } else {
            index++;
        }
    }
    throw new IllegalArgumentException("Key not found");
}

这是FUI uses getIndexForKey(String) 的方式。

只要您不下载可笑的大列表,就可以在性能上很好地遍历列表。否则,您可以使用Map<String, Integer>并查看FUI here的尝试。

PS:您的onChildAdded代码插入错误(项目总是添加在末尾,即使它们在中间)。看看如何FUI does this

07-27 13:34