【问题标题】:How to update an element in ArrayList without knowing index in Android with Firebase Realtime Database?如何使用 Firebase 实时数据库在不知道 Android 索引的情况下更新 ArrayList 中的元素?
【发布时间】:2018-06-09 00:12:22
【问题描述】:

我有一个简单的 RecyclerView,其中 CardView 作为列表项。从 Firebase 实时数据库检索并存储到 noteList 的列表中的每个项目。 Firebase sdk 为 onChildAdded、onChildChanged 和其他少数几个提供回调。现在我设计了用于回收器视图的适配器以接收 ArrayList。每当实时数据库中的数据发生更改时,我都会使用回调向noteList 添加或删除项目。每当特定项目的值发生更改时,都会调用 onChildChanged 方法。我想在noteList 中反映这种变化并通知适配器。 当然,我们可以天真地搜索 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 是一个扩展函数。 (检查代码中的 cmets 以获取回调名称)

由于dataSnapshot 只能告诉我们更改的键和值(据我从文档中知道),我将如何在不知道更改元素索引的情况下更新noteList?或者真的有办法获取索引吗?

【问题讨论】:

    标签: android firebase arraylist firebase-realtime-database kotlin


    【解决方案1】:

    到目前为止,我建议您使用专为您的用例构建的 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&lt;String, Integer&gt; 并查看 FUI here 的尝试。

    PS:您的 onChildAdded 代码对于插入是错误的(即使项目在中间,也会始终添加到末尾)。看看如何FUI does this

    【讨论】:

    • 谢谢。我将使用 Firebase ui。顺便说一句,我认为列表中的项目附加在末尾(基于时间戳),因此 onChildAdded 中的代码。谢谢指正。
    • 好吧,push() 方法确实根据时间戳创建键,并且默认查询顺序是按字母顺序排列的,但是假设您想要获得最多支持的帖子或其他内容。你可以写query.orderByChild("votes"),然后无论他们的密钥如何,孩子都可以添加到任何地方。我只是让你免于未来的痛苦。 ?
    猜你喜欢
    • 1970-01-01
    • 2019-05-13
    • 2023-03-04
    • 2020-06-02
    • 2017-03-05
    • 2021-04-27
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多