Простая вещь, которую я хотел бы сделать (см. на картинке)
Отображать представление с информацией, поступающей из 2 разных мест в Firebase, чтобы оно вело себя профессионально, прокручивая ВВЕРХ и ВНИЗ
У меня есть список фильмов и по каждому из них я бы хотел, чтобы пользователь указал рейтинг и увидел его
В БД я создал 2 структуры, чтобы иметь список фильмов с одной стороны и рейтинги для каждого пользователя с другой.
Проблема с использованием FirebaseRecyclerAdapter
Моя проблема в том, что при быстрой прокрутке вверх и вниз по списку визуализация информации, поступающей от второй ссылки (рейтинг), загружается в разное время (асинхронный вызов), и это неприемлемо для просмотра. это (небольшая) задержка построения представления. Является ли это ограничением FirebaseRecyclerView?
Поскольку viewHolder повторно используются в recycleView, я сбрасываю и перезагружаю каждый раз в populateView() значения рейтинга, и это не помогает. После получения я обязан получить их снова, если пользователь прокручивает представление (см. setOnlistener в populateView()
Установка прослушивателя в populateView также приводит к тому, что количество прослушивателей будет равно количеству выполнений populateView() (если вы прокручиваете ВВЕРХ и ВНИЗ, это будет много раз).
Решения / Обходной путь?
Есть ли правильный способ сделать это, чтобы предотвратить проблему? Или это ограничение? Как насчет производительности с моей реализацией, где прослушиватель находится внутри populateView() и создано МНОГОЕ прослушивателей?
Ниже некоторые вещи, о которых я думаю:
- Предотвратить повторное использование viewHolder и просто загрузить один раз?
- Переопределить некоторые другие методы RecyclerView? Я пробовал использовать parseSnapshot(), но та же проблема...
- Измените структуру БД, чтобы вся информация была в одном списке (я не думаю, что это хорошо, потому что это означает добавление информации о рейтинге каждого пользователя в список фильмов)
- Добавьте счетчик загрузки в часть рейтинга, чтобы рейтинг отображался только после завершения асинхронного вызова firebase (не нравится) без эффекта сегодняшнего дня: «изменение цвета звезды перед пользователем».
Моя реализация
Из FirebaseRecyclerAdapter
@Override
protected void populateViewHolder(final MovieViewHolder viewHolder, final Movie movie, final int position) {
String movieId = this.getRef(position).getKey();
// Oblidged to show no rating at the beginning because otherwise
// if a viewHolder is reused it has the values from another movie
viewHolder.showNoRating();
//---------------------------------------------
// Set values in the viewHolder from the model
//---------------------------------------------
viewHolder.movieTitle.setText(movie.getTitle());
viewHolder.movieDescription.setText(movie.getDescription());
//-----------------------------------------------------
// Ratings info are in another DB location... get them
// but call is asynchronous so PROBLEM when SCROLLING!
//-----------------------------------------------------
DatabaseReference ratingMovieRef = mDbRef.child(Constants.FIREBASE_LOCATION_RATINGS).child(currentUserId).child(movieId);
ratingQuoteRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
RatingMovie ratingMovie = dataSnapshot.getValue(RatingMovie.class);
Rating rating = Rating.NO_RATING;
if (ratingMovie != null) {
rating = Rating.valueOf(ratingMovie.getRating());
}
// Set the rating in the viewholder (through anhelper method)
viewHolder.showActiveRating(rating);
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
из MovieViewHolder
public class QuoteViewHolder extends RecyclerView.ViewHolder {
public CardView cardView;
public TextView movieTitle;
public TextView movieDescription;
public ImageView ratingOneStar;
public ImageView ratingTwoStar;
public ImageView ratingThreeStar;
public QuoteViewHolder(View itemView) {
super(itemView);
movieTitle = (TextView)itemView.findViewById(R.id.movie_title);
movieDescription = (TextView)itemView.findViewById(R.id.movie_descr);
// rating
ratingOneStar = (ImageView)itemView.findViewById(R.id.rating_one);
ratingTwoStar = (ImageView)itemView.findViewById(R.id.rating_two);
ratingThreeStar = (ImageView)itemView.findViewById(R.id.rating_three);
}
/**
* Helper to show the color on stars depending on rating value
*/
public void showActiveRating(Rating rating){
if (rating.equals(Rating.ONE)) {
// just set the good color on ratingOneStar and the others
...
}
else if (rating.equals(Rating.TWO)) {
// just set the good color
...
} else if (rating.equals(Rating.THREE)) {
// just set the good color
...
}
/**
* Initialize the rating icons to unselected.
* Important because the view holder can be reused and if not initalised values from other moviecan be seen
*/
public void initialiseNoRating(){
ratingOneStar.setColorFilter(ContextCompat.getColor(itemView.getContext(), R.color.light_grey));
ratingTwoStar.setColorFilter(....
ratingThreeStar.SetColorFilter(...
}