android - 如何使用 Firebase 实时数据库在不知道 Android 索引的情况下更新 ArrayList 中的元素?

标签 android firebase arraylist firebase-realtime-database kotlin

我有一个简单的 RecyclerView,其中 CardView 作为列表项。列表中的每一项都从 Firebase 实时数据库中检索并存储到 noteList。 Firebase sdk 为 onChildAdded、onChildChanged 和其他几个提供回调。现在我已经设计了用于回收器 View 的适配器来接收 ArrayList。每当实时数据库中的数据发生变化时,我都会使用回调向 noteList 添加或删除项目。 onChildChanged 方法在特定项目的值发生变化时被调用。我想在 noteList 中反射(reflect)这一变化并通知适配器。 当然,我们可以天真地搜索 List 中与更改元素的键匹配的每个元素并更新它。但这可以以更好/更有效的方式完成吗?

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 的尝试.

附言:你的onChildAdded插入代码错误(项目将始终添加到末尾,即使它们位于中间)。看看如何FUI does this .

关于android - 如何使用 Firebase 实时数据库在不知道 Android 索引的情况下更新 ArrayList 中的元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48007595/

相关文章:

android - CoordinatorLayout 和 RecyclerView 问题

ios - 从 Firebase 检索数据后对其进行操作

Java/MySql - 获取一行并将其转换为 arraylist<String>

java - 如何遍历 2 个列表并检查一个元素的内容是否与不同列表中的另一个元素相同?

java - 递归方法打印太多次?

android - 用于任何 Activity 的静态数据库类

Android缩放动画到指定尺寸

android - 错误 : 'gint' has not been declared

android - 通知设置 channel 和 FCM subscribeToTopic 有什么不同?

ios - Firebase App Distribution 获取注册测试人员的 UDID