我有一个简单的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。