Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 具有2个不同数据库引用的FirebaseRecyclerAdapter-对滚动产生负面影响_Android_Firebase_Firebase Realtime Database_Android Recyclerview_Android Viewholder - Fatal编程技术网

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

Android 具有2个不同数据库引用的FirebaseRecyclerAdapter-对滚动产生负面影响,android,firebase,firebase-realtime-database,android-recyclerview,android-viewholder,Android,Firebase,Firebase Realtime Database,Android Recyclerview,Android Viewholder,我想做的简单事情(如图所示) 显示一个视图,其中包含来自Firebase中两个不同位置的信息,以便它以专业的方式上下滚动 我有一个电影列表,我希望用户在每个列表上指定一个分级并观看 在DB中,我创建了两个结构,一边是电影列表,另一边是每个用户的收视率 使用FirebaseRecyclerAdapter时出现问题 我的问题是,快速上下滚动列表,来自第二个参考(评级)的信息的可视化在不同的时间加载(异步调用),这是不可接受的,无法看到构建视图的这种(小)延迟。这是FirebaseRecyclerVi

我想做的简单事情(如图所示) 显示一个视图,其中包含来自Firebase中两个不同位置的信息,以便它以专业的方式上下滚动

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

在DB中,我创建了两个结构,一边是电影列表,另一边是每个用户的收视率

使用FirebaseRecyclerAdapter时出现问题 我的问题是,快速上下滚动列表,来自第二个参考(评级)的信息的可视化在不同的时间加载(异步调用),这是不可接受的,无法看到构建视图的这种(小)延迟。这是FirebaseRecyclerView的限制吗

因为视图持有者在recycleView中重复使用,所以每次在populateView()中重置并重新加载评级值时,我都会重置并重新加载,这没有帮助。一旦检索到,如果用户滚动视图,我有义务再次获取它们(请参阅populateView()中的setOnlistener

在populateView中设置监听器也会导致监听器的数量与执行populateView()的次数相同(如果上下滚动多次)。

解决方案/变通方法? 是否有一种正确的方法来防止问题发生?或者是一种限制? 如果侦听器位于populateView()中,并且创建了许多侦听器,那么我的实现的性能如何

下面是我正在思考的一些事情:

  • 防止取景器被回收,只需加载一次
  • 重写RecyclerView的其他一些方法?我尝试了parseSnapshot(),但问题是相同的
  • 将DB结构更改为将所有信息都放在一个列表中(我认为这不是一个好的列表,因为它意味着将每个用户的评级信息添加到电影列表中)
  • 在分级部分添加一个加载微调器,以便只有在完成对firebase的异步调用(不喜欢)时才显示分级,而不会产生“在用户面前更改星光颜色”的效果
我的实现 来自FirebaseRecyclerAdapter

@覆盖
受保护的void populateViewHolder(最终电影viewHolder viewHolder、最终电影电影、最终int位置){
String movieId=this.getRef(position.getKey();
//由于其他原因,在开始时有义务不显示评级
//如果重新使用viewHolder,则它具有来自其他电影的值
viewHolder.showNoRating();
//---------------------------------------------
//在模型的viewHolder中设置值
//---------------------------------------------
viewHolder.movieTitle.setText(movie.getTitle());
viewHolder.movieDescription.setText(movie.getDescription());
//-----------------------------------------------------
//评级信息在另一个数据库位置…获取它们
//但调用是异步的,所以滚动时会出现问题!
//-----------------------------------------------------
DatabaseReference ratingMovieRef=mDbRef.child(Constants.FIREBASE\u LOCATION\u RATINGS).child(currentUserId).child(movieId);
ratingQuoteRef.addListenerForSingleValueEvent(新值EventListener()){
@凌驾
公共void onDataChange(DataSnapshot DataSnapshot){
RatingMovie RatingMovie=dataSnapshot.getValue(RatingMovie.class);
额定值=额定值。无额定值;
if(分级电影!=null){
rating=rating.valueOf(ratingMovie.getRating());
}
//在viewholder中设置分级(通过帮助方法)
viewHolder.showActiveRating(额定值);
}
@凌驾
已取消的公共void(DatabaseError DatabaseError){
}
});
}
来自MovieViewHolder

public类QuoteViewHolder扩展了RecyclerView.ViewHolder{
公共卡视图卡视图;
公共文本视图电影;
公共文本视图电影描述;
公共图像浏览率NESTAR;
公众形象评价双星;
公共图像浏览率三星;
公共QuoteView文件夹(查看项目视图){
超级(项目视图);
movieTitle=(TextView)itemView.findViewById(R.id.movie\u title);
movieDescription=(TextView)itemView.findViewById(R.id.movie\u descr);
//评级
RatingNestar=(ImageView)itemView.findViewById(R.id.rating_one);
ratingTwoStar=(ImageView)itemView.findViewById(R.id.rating_-two);
RatingTreestar=(ImageView)itemView.findViewById(R.id.rating_三);
}
/**
*帮助器,根据额定值显示星星上的颜色
*/
公共评级(评级){
if(额定值等于(额定值1)){
//只需在RatingNestar和其他产品上设置好颜色
...
}
否则如果(额定值等于(额定值2)){
//把颜色调好就行了
...
}否则如果(额定值等于(额定值三)){
//把颜色调好就行了
...
}
/**
*将分级图标初始化为未选择。
*重要的是,视图支架可以重复使用,如果没有其他电影的初始值,则可以看到
*/
公共无效初始值忽略(){
RatingNestar.setColorFilter(ContextCompat.getColor(itemView.getContext(),R.color.light_Gray));
ratingTwoStar.setColorFilter(。。。。
RatingTreestar.SetColorFilter(。。。
}

您可以使用ChildEventListener对分级进行排序缓存。基本上只需为分级节点创建一个单独的分级,并让它将分级存储在映射中。然后使用RecyclerAdapter,如果分级可用,您将从映射中检索分级,如果不可用,则让分级侦听器在收到分级后尽快更新recyclerviewnloaded评级。这是您可以采用的一种策略,要做到这一点,您必须手动复制/粘贴FirebaseUI库中的某些类,并为此设置一些公共字段
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));
        }
    };
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);
        }
    }
}