2017-12-28 8 views
2

CardView를 사용한 간단한 RecyclerView가 목록 항목으로 있습니다. Firebase Realtime 데이터베이스에서 검색된 목록의 각 항목은 noteList에 저장됩니다. Firebase SDK는 onChildAdded, onChildChanged 및 기타 몇몇 콜백을 제공합니다. 이제 ArrayList를 사용할 리무버보기 용 어댑터를 설계했습니다. 실시간 데이터베이스의 데이터가 변경 될 때마다 콜백을 사용하여 noteList에 항목을 추가하거나 제거합니다. onChildChanged 메서드는 특정 항목의 값이 변경 될 때마다 호출됩니다. 이 변경 내용을 noteList에 반영하고 해당 어댑터에 알리고 싶습니다. 물론, 변경된 요소의 키와 일치하는 List의 각 요소를 순식간에 검색하고 업데이트 할 수 있습니다. 그러나 이것이 더 효율적이고 효과적인 방법으로 행해질 수 있습니까?Firebase Realtime Database로 안드로이드의 색인을 몰라도 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의 시도를 참조하십시오.

추신 : onChildAdded 삽입 코드가 잘못되었습니다 (중간에 있어도 항목이 항상 끝에 추가됩니다). 보십시오 FUI does this 어떻게보십시오.

+0

감사합니다. 나는 Firebase와 함께 갈 것이다. Btw, 나는 목록의 항목을 (타임 스탬프에 따라) 끝에 추가 했으므로 onChildAdded의 코드를 추가했다고 생각했습니다. 수정 해줘서 고마워. –

+1

글쎄, push() 메소드는 타임 스탬프를 기반으로 키를 생성하고 기본 쿼리 순서는 알파벳 순서이지만 가장 많이지지 된 게시물이나 뭔가를 얻고 싶다고 가정 해 봅시다. 'query.orderByChild ("votes")'라고 쓰면 아이들은 키에 관계없이 어디에서나 추가 될 수 있습니다. 미래의 고통에서 너를 구해줄 뿐이야. – SUPERCILEX

관련 문제