Acoplando FirebaseRecyclerViewAdapter a un Boolean / String Map.Entry

Estoy usando el FirebaseRecyclerViewAdapter de la com.firebaseui:firebase-ui:0.2.0 en muchas ubicaciones de mi aplicación. Mi pregunta es cómo aplicarlo en situaciones donde el argumento de consulta devuelve una cantidad de valores de entrada ‘indexados’ (Map.Entry).

Como se indica en la documentación de Firebase ( https://www.firebase.com/docs/android/guide/structuring-data.html ), estoy usando índices para mantener la estructura de datos plana. Esto me lleva a una situación en la que debo vincular estos índices a mi ViewHolder. En el método de vista de relleno, estoy usando la clave del índice para recuperar los datos con los que llenar el visitante.

Tengo problemas para crear el adaptador, no estoy seguro de cómo definir el argumento ‘modelClass’ en el caso de un Boolean / String Map. Entrada:

 mAdapter = new FirebaseRecyclerViewAdapter<Map.Entry, ItemViewHolder>(???.class, R.layout.my_card, ItemViewHolder.class, getItemIndexQuery(mKey) ) { ... } 

Su valor es un Boolean , no un Map . Por lo tanto, su comentario es correcto: deberá especificar Boolean / Boolean.class para el tipo de valor. Para poder buscar la clave, deberá actualizar a FirebaseUI-Android 0.2.2. En ese lanzamiento, agregamos una sobrecarga populateViewHolder(VH, T, int) que obtiene la posición del elemento como parámetro. Con eso, puedes buscar la clave del artículo.

Diga que esta es su estructura JSON:

 { "items": { "pushid1": "Fri Jan 01 2016 16:40:54 GMT-0800 (PST)", "pushid2": "Fri Jan 01 2016 16:41:07 GMT-0800 (PST)", "pushid3": "Fri Jan 01 2016 16:41:25 GMT-0800 (PST)", "pushid4": "Fri Jan 01 2016 16:41:37 GMT-0800 (PST)", "pushid5": "Fri Jan 01 2016 16:42:04 GMT-0800 (PST)" }, "index": { "pushid1": true, "pushid3": true, "pushid5": true } } 

Así que almacenamos cadenas que representan la fecha / hora y tenemos un índice para seleccionar un subconjunto de estos elementos.

Ahora podemos cargar los nodos del índice, luego cargar los elementos a los que se refieren esos nodos y mostrarlos en las vistas con:

 FirebaseRecyclerViewAdapter adapter = new FirebaseRecyclerViewAdapter( Boolean.class, android.R.layout.two_line_list_item, ItemViewHolder.class, ref.child("index")){ protected void populateViewHolder(final ItemViewHolder viewHolder, Boolean model, int position) { String key = this.getRef(position).getKey(); ref.child("items").child(key).addListenerForSingleValueEvent(new ValueEventListener() { public void onDataChange(DataSnapshot dataSnapshot) { String date = dataSnapshot.getValue(String.class); ((TextView)viewHolder.itemView.findViewById(android.R.id.text1)).setText(date); } public void onCancelled(FirebaseError firebaseError) { } }); } }; 

La salida en la pantalla:

Aplicación de Android que muestra tres fechas

Para obtener el código completo, consulte Activity34559171 en este repository .

Enfrenté el mismo problema y finalmente encontré esta clase: FirebaseIndexRecyclerAdapter, que funciona perfectamente para mí.

Editar 4

Abandoné el código a continuación, era basura. 🙁 No lo use. Reescribí la parte de la base de datos de Firebase-UI , así que utilícela.

Ediciones 1, 2 y 3

Dado que addListenerForSingleValueEvent significa que los datos serán estáticos (a menos que cambie el valor de la clave), esta es mi manera de evitar los datos estáticos sin cambiar el valor de la clave:

Crea una lista de oyentes de eventos y objetos de soporte:

 private Map mValueEventListeners = new ArrayMap<>(); private List mTeamInfoList = new ArrayList<>(); 

FirebaseRecyclerAdapter :

 RecyclerView recyclerView = (RecyclerView) findViewById(R.id.content_main_recycler_view); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerViewAdapter = new FirebaseRecyclerAdapter( Long.class, R.layout.activity_main_row_layout, TeamHolder.class, Utils.getDatabase() .getReference() .child(Constants.FIREBASE_TEAM_INDEXES) .child(mUser.getUid()) .orderByValue()) { @Override public void populateViewHolder(final TeamHolder teamHolder, Long teamNumberDoNotUse, final int position) { DatabaseReference databaseReference = Utils.getDatabase() .getReference() .child(Constants.FIREBASE_TEAMS) .child(getRef(position).getKey()); if (!mValueEventListeners.containsKey(databaseReference)) { ValueEventListener valueEventListener = new ValueEventListener() { public void onDataChange(DataSnapshot dataSnapshot) { if (dataSnapshot.getValue() != null) { TeamInfo teamInfo = dataSnapshot.getValue(TeamInfo.class); if (position >= mTeamInfoList.size()) { String teamNumber = teamInfo.getNumber(); teamHolder.setTeamNumber(teamNumber); teamHolder.setTeamName(teamInfo.getName(), MainActivity.this.getString(R.string.no_name)); teamHolder.setTeamLogo(teamInfo.getMedia(), MainActivity.this); teamHolder.setListItemClickListener(teamNumber, MainActivity.this, dataSnapshot.getKey()); teamHolder.setCreateNewScoutListener(teamNumber, MainActivity.this, dataSnapshot.getKey()); mTeamInfoList.add(teamInfo); } else { mTeamInfoList.set(position, teamInfo); notifyItemChanged(position); } } else { // This should never happen since we are caching this offline FirebaseCrash.report(new IllegalStateException( "MainActivity RecyclerView event listener had null value (ref: " + dataSnapshot.getRef() + "pointed to non existent data)")); } } public void onCancelled(DatabaseError databaseError) { FirebaseCrash.report(databaseError.toException()); } }; databaseReference.addValueEventListener(valueEventListener); mValueEventListeners.put(databaseReference, valueEventListener); } else { String teamNumber = mTeamInfoList.get(position).getNumber(); teamHolder.setTeamNumber(teamNumber); teamHolder.setTeamName(mTeamInfoList.get(position).getName(), MainActivity.this.getString(R.string.no_name)); teamHolder.setTeamLogo(mTeamInfoList.get(position).getMedia(), MainActivity.this); teamHolder.setListItemClickListener(teamNumber, MainActivity.this, getRef(position).getKey()); teamHolder.setCreateNewScoutListener(teamNumber, MainActivity.this, getRef(position).getKey()); } } }; recyclerView.setAdapter(mRecyclerViewAdapter); 

En su OnDestroy :

 @Override protected void onDestroy() { super.onDestroy(); if (mRecyclerViewAdapter != null) { mRecyclerViewAdapter.cleanup(); } for (DatabaseReference databaseReference : mValueEventListeners.keySet()) { databaseReference.removeEventListener(mValueEventListeners.get(databaseReference)); } }