2017-12-28 35 views
2

私はリストアイテムとしてCardViewを持つ単純なRecyclerViewを持っています。 Firebase Realtimeデータベースから取得したリストの各項目はnoteListに保存されます。 Firebase sdkは、onChildAdded、onChildChangedなどのコールバックを提供します。今度は、リサイクラー・ビュー用のアダプターをArrayListで使用するように設計しました。 Realtimeデータベースのデータが変更されるたびに、コールバックを使用してnoteListに項目を追加または削除します。 onChildChangedメソッドは、特定の項目の値が変更されるたびに呼び出されます。この変更をnoteListに反映させ、同じことをアダプターに通知したいと思います。 もちろん、変更された要素のキーと一致するList内の各要素を素早く検索して更新することができます。しかし、これはより効率的な方法で行うことができますか?Firebase Realtime DatabaseでAndroidのインデックスを知らずにArrayListの要素を更新するにはどうすればいいですか?

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は、拡張機能です。どのように私はのインデックスを知らなくてもnoteListを更新する、(私はドキュメントから知っている限り)dataSnapshot以来

は私たちだけ変更されたキーと値を伝えることができます(コールバックの名前をコード内のコメントをご確認ください)変更された要素?または、実際にインデックスを取得する方法はありますか?

答えて

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<String, Integer>を使用し、FUI hereの試行を参照してください。

PS:あなたのonChildAddedコードは挿入には間違っています(アイテムは途中であっても最後に追加されます)。どのようにFUI does thisを参照してください。

+0

ありがとうございました。私はFirebaseと一緒に行きます。 Btw、私はリストの項目を(タイムスタンプに基づいて)末尾に追加したので、onChildAddedのコードを追加したと思った。訂正してくれてありがとう。 –

+1

'push()'メソッドは、タイムスタンプに基づいてキーを作成し、デフォルトのクエリの順序はアルファベット順ですが、あなたが最も賞賛された投稿などを取得したいとしましょう。 'query.orderByChild(" votes ")'と書いておけば、子はキーに関係なくどこにでも追加できます。私は将来の痛みからあなたを救うだけです。 – SUPERCILEX

関連する問題