gpt4 book ai didi

android - 具有 2 个不同数据库引用的 FirebaseRecyclerAdapter - 对滚动的负面影响

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:13:22 26 4
gpt4 key购买 nike

enter image description here

我想做的简单事情(见图片)

显示一个 View ,其中包含来自 Firebase 中 2 个不同位置的信息,以便它以专业的方式向上和向下滚动

我有一个电影列表,我希望用户在每个电影上指定一个评级并查看它

在 DB 中,我创建了 2 个结构,一侧是电影列表,另一侧是每个用户的评分

使用 FirebaseRecyclerAdapter 的问题

我的问题是快速上下滚动列表,来自第二个引用(评级)的信息的可视化是在不同的时间(异步调用)加载的,这不是看到这个(小)延迟构建 View 是可以接受的。这是 FirebaseRecyclerView 的限制吗?

因为 viewHolders 在 recycleView 中重复使用,我每次在 populateView() 中重置并重新加载评级值,这没有帮助。一旦检索到,如果用户 ScrollView ,我有义务再次获取它们(请参阅 populateView() 中的 setOnlistener

在 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(...
}

最佳答案

您可以使用 ChildEventListener 来缓存评级。基本上只是为评级节点创建一个单独的节点,并将评级存储在 map 中。然后使用 RecyclerAdapter,如果评级可用,您将从 map 中检索,如果评级不可用,则让评级监听器在下载评级后立即更新 recyclerview。这是您可以采用的一种策略,要做到这一点,您将不得不从 FirebaseUI 库中手动复制/粘贴一些类,并将一些字段设置为 public 以使其起作用。

用法是这样的

private MovieRatingConnection ratingConnection;

// inside onCreate

ratingConnection = new MovieRatingConnection(userId, new MovieRatingConnection.RatingChangeListener() {
@Override
public void onRatingChanged(DataSnapshot dataSnapshot) {
if (recyclerAdapter != null) {
if (dataSnapshot != null) {
int index = recyclerAdapter.snapshots.getIndexForKey(dataSnapshot.getKey());
recyclerAdapter.notifyItemChanged(index);
}
}
}
});

Query movieQuery = FirebaseDatabase.getInstance().getReference().child("Movies");
recyclerAdapter = new FirebaseRecyclerAdapter(movieQuery...) {
@Override
public void populateViewHolder(RecyclerView.ViewHolder viewHolder, Object model, int position) {
//...
final String key = getRef(position).getKey();
viewHolder.showActiveRating(ratingConnection.getRating(key));
}
};

MovieRatingConnection 就是这样一个类

public class MovieRatingConnection {

private MovieRatingListener listener;

public MovieRatingConnection(String userId, RatingChangeListener changeListener) {
Query query = FirebaseDatabase.getInstance().getReference().child("MovieRatings").child(userId);
listener = new MovieRatingListener(query, changeListener);
}

public Rating getRating(String key) {
return listener.getRating(key);
}

public void cleanup() {
if (listener != null) {
listener.unregister();
}
}



public static class MovieRatingListener implements ChildEventListener {

public interface RatingChangeListener {
public void onRatingChanged(DataSnapshot snapshot);

}

private Query query;
private HashMap<String, Rating> ratingMap = new HashMap<>();
private RatingChangeListener changeListener;


public MovieRatingListener(Query query, RatingChangeListener changeListener) {
this.query = query;
this.changeListener = changeListener;
query.addChildEventListener(this);

}

@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
ratingMap.put(dataSnapshot.getKey(), dataSnapshot.getValue(Rating.class));
changeListener.onRatingChanged(dataSnapshot);
}
}

@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null) {
ratingMap.put(dataSnapshot.getKey(), dataSnapshot.getValue(Rating.class));
changeListener.onRatingChanged(dataSnapshot);
}
}

@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
ratingMap.remove(dataSnapshot.getKey());
changeListener.onRatingChanged(null);
}

@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {

}

@Override
public void onCancelled(DatabaseError databaseError) {

}

public Rating getRating(String key) {
if (ratingMap.get(key) != null) {
return ratingMap.get(key);
} else {
return new Rating(); // default value/null object
}
}

public void unregister() {
query.removeEventListener(this);
}
}
}

关于android - 具有 2 个不同数据库引用的 FirebaseRecyclerAdapter - 对滚动的负面影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42489640/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com