添加或删除的Firebase Firestore上的RecyclerView项重复

时间:2019-01-11 01:01:21

标签: android firebase listview android-recyclerview google-cloud-firestore

我正在使用Firebase firestore作为数据库构建一个应用程序,我添加了分页功能,但它的工作原理是,当从应用程序添加或删除数据时,回收项目重复出现,有时会重复到3、4个位置,有时它弄乱了安排。尝试搜索解决方案并最终覆盖了以下方法:

@Override
public long getItemId(int position) {
    return super.getItemId(position);
}

@Override
public int getItemViewType(int position) {
    return position;
}

并添加

setHasStableIds(true);

但仍然没有运气,这是我的代码片段:

public class HomeFragment extends Fragment {

private View view;
private LinearLayout mNoMedia;
private RecyclerView mMediaList;
private SwipeRefreshLayout mSwipe;
private TextView mNoInternet;

private FirebaseAuth mAuth;
private FirebaseFirestore firebaseFirestore;

private List<PostModel> postModelList;
private PostAdapter postAdapter;
private DocumentSnapshot lastVisible;
private Boolean isFirstPageFirstLoad;
private String currentUserId;
private final int NUM_COLUMNS = 2;
private StaggeredGridLayoutManager staggeredGridLayoutManager;

public HomeFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    if (view == null) {
        view = inflater.inflate(R.layout.fragment_home, container, false);

        mAuth = FirebaseAuth.getInstance();
        firebaseFirestore = FirebaseFirestore.getInstance();

        mSwipe = view.findViewById(R.id.mainSwipe);
        mMediaList = view.findViewById(R.id.mediaList);
        mNoInternet = view.findViewById(R.id.no_internet);
        postModelList = new ArrayList<>();

        staggeredGridLayoutManager = new StaggeredGridLayoutManager(NUM_COLUMNS, StaggeredGridLayoutManager.VERTICAL);
        postAdapter = new PostAdapter(postModelList);
        postAdapter.setHasStableIds(true);

        mMediaList.setLayoutManager(staggeredGridLayoutManager);
        mMediaList.hasFixedSize();
        mMediaList.setHasFixedSize(true);
        mMediaList.setItemAnimator(null);
        mMediaList.setAdapter(postAdapter);

        mNoMedia = view.findViewById(R.id.mainMediaLin);

        //=========================== Functions ====================================================
        try {
            if (getActivity() != null) {
                if (mAuth.getCurrentUser() != null) {
                    currentUserId = mAuth.getCurrentUser().getUid();

                        loadPost();
                    } else {
                        mNoMedia.setVisibility(View.VISIBLE);
                        mNoInternet.setVisibility(View.VISIBLE);
                    }
                } else {
                    mNoMedia.setVisibility(View.VISIBLE);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return view;
}

private void loadPost() {
    Query firstQuery = firebaseFirestore.collection("TubbePosts")
            .document(currentUserId).collection("Posts")
            .orderBy("utc", Query.Direction.DESCENDING).limit(8);
    firstQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(@javax.annotation.Nullable QuerySnapshot queryDocumentSnapshots, @javax.annotation.Nullable FirebaseFirestoreException e) {
            if (queryDocumentSnapshots != null) {

                if (!queryDocumentSnapshots.isEmpty()) {
                    if (isFirstPageFirstLoad) {
                        lastVisible = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);
                        postModelList.clear();
                    }
                    for (@NonNull DocumentChange doc : queryDocumentSnapshots.getDocumentChanges()) {
                        if (doc.getType() == DocumentChange.Type.ADDED) {

                            mNoMedia.setVisibility(View.GONE);
                            String docId = doc.getDocument().getId();
                            final PostModel postModel = doc.getDocument().toObject(PostModel.class).withId(docId);

                            if (isFirstPageFirstLoad) {
                                postModelList.add(postModel);
                            } else {
                                postModelList.add(0, postModel);
                            }
                            postAdapter.notifyDataSetChanged();

                        }
                    }

                    isFirstPageFirstLoad = false;
                }
            }
        }
    });
}

public void loadMorePost() {

            Query nextQuery = firebaseFirestore.collection("TubbePosts")
                    .document(currentUserId).collection("Posts")
                    .orderBy("utc", Query.Direction.DESCENDING)
                    .startAfter(lastVisible).limit(8);
            nextQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
                @Override
                public void onEvent(@javax.annotation.Nullable QuerySnapshot queryDocumentSnapshots, @javax.annotation.Nullable FirebaseFirestoreException e) {
                    if (queryDocumentSnapshots != null) {
                        if (!queryDocumentSnapshots.isEmpty()) {
                            lastVisible = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);

                            for (@NonNull DocumentChange doc : queryDocumentSnapshots.getDocumentChanges()) {
                                if (doc.getType() == DocumentChange.Type.ADDED) {
                                    String docId = doc.getDocument().getId();
                                    @NonNull final PostModel postModel = doc.getDocument().toObject(PostModel.class).withId(docId);

                                    postModelList.add(postModel);
                                    postAdapter.notifyDataSetChanged();

                                }
                            }
                        }
                    }
                }
            });

}

我的适配器:

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> {

private List<PostModel> postList;
private Context context;
private FirebaseFirestore firebaseFirestore;
private FirebaseAuth firebaseAuth;
private String img = null;
private RequestOptions placeholder;
private String userId, id;
private int ref;

public PostAdapter(List<PostModel> postList) {
    this.postList = postList;
}

@NonNull
@Override
public PostAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_item, parent, false);
    context = parent.getContext();
    firebaseFirestore = FirebaseFirestore.getInstance();
    firebaseAuth = FirebaseAuth.getInstance();
    return new PostAdapter.ViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull PostAdapter.ViewHolder holder, int position) {

    holder.setIsRecyclable(false);

    try {
        final String docId = postList.get(position).DocId;
        final String currentUserId = firebaseAuth.getCurrentUser().getUid();

        String postId = postList.get(position).getPostId();
        String posterId = postList.get(position).getPosterId();
        String descText = postList.get(position).getDescText();
        String mediaUrl = postList.get(position).getMediaUrl();
        String format = postList.get(position).getFormat();
        long utcTime = postList.get(position).getUtc().getTime();
        String utc = postList.get(position).getUtc().toString();

        if (format.equals("image")) {
            holder.setImg(mediaUrl);

        } else if (format.equals("video")) {
            holder.mPlay.setVisibility(View.VISIBLE);
            holder.setVideoImg(mediaUrl);
        }
        holder.mTime.setText(getTimeAgo(utcTime, context));
        holder.mDesc.setText(descText);

        firebaseFirestore.collection("TubbePosts").document(posterId)
                .collection("Posts")
                .document(postId).addSnapshotListener(new EventListener<DocumentSnapshot>() {
            @Override
            public void onEvent(@javax.annotation.Nullable DocumentSnapshot documentSnapshot, @javax.annotation.Nullable FirebaseFirestoreException e) {
                if (documentSnapshot != null) {
                    if (!documentSnapshot.exists()) {
                        try {
                            userId = currentUserId;
                            id = postId;
                            ref = position;

                            new DeleteProcess().execute();

                        } catch (Exception f) {
                            f.printStackTrace();
                        }
                    }
                }
            }
        });

        firebaseFirestore.collection("Users").document(posterId)
                .addSnapshotListener(new EventListener<DocumentSnapshot>() {
                    @Override
                    public void onEvent(@javax.annotation.Nullable DocumentSnapshot documentSnapshot,
                                        @javax.annotation.Nullable FirebaseFirestoreException e) {
                        try {
                            if (documentSnapshot != null) {
                                if (documentSnapshot.exists()) {
                                    String image = documentSnapshot.getString("image");
                                    holder.setUserImg(image);
                                    img = image;
                                }
                            }

                        } catch (Exception f) {
                            f.printStackTrace();
                        }
                    }
                });

        firebaseFirestore.collection("TubbePosts").document(posterId)
                .collection("Posts")
                .document(postId).collection("Likes")
                .addSnapshotListener(new EventListener<QuerySnapshot>() {
                    @Override
                    public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
                        if (queryDocumentSnapshots != null) {
                            if (!queryDocumentSnapshots.isEmpty()) {
                                int count = queryDocumentSnapshots.size();
                                if (count < 1000) {
                                    holder.mLikeCount.setText(count + "");
                                } else {
                                    holder.mLikeCount.setText(getCount(count));
                                }
                            } else {
                                holder.mLikeCount.setText("0");
                            }
                        }
                    }
                });

        firebaseFirestore.collection("TubbePosts").document(posterId)
                .collection("Posts").document(postId).collection("Likes")
                .document(currentUserId).addSnapshotListener(new EventListener<DocumentSnapshot>() {
            @Override
            public void onEvent(@Nullable DocumentSnapshot documentSnapshot, @Nullable FirebaseFirestoreException e) {
                if (documentSnapshot != null) {
                    if (documentSnapshot.exists()) {
                        holder.mLikeBtn.setImageDrawable(context.getResources().getDrawable(R.mipmap.heart_selected));
                    } else {
                        holder.mLikeBtn.setImageDrawable(context.getResources().getDrawable(R.mipmap.heart));
                    }
                }
            }
        });

        holder.mLikeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isConnected(context)) {
                    firebaseFirestore.collection("TubbePosts")
                            .document(posterId)
                            .collection("Posts")
                            .document(postId).collection("Likes")
                            .document(currentUserId).get()
                            .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                                @Override
                                public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                                    if (task.isSuccessful()) {
                                        if (task.getResult().exists()) {
                                            firebaseFirestore.collection("TubbePosts")
                                                    .document(posterId)
                                                    .collection("Posts")
                                                    .document(postId).collection("Likes")
                                                    .document(currentUserId).delete();
                                        } else {
                                            Date utc = new Date(System.currentTimeMillis());
                                            Map<String, Object> likesMap = new HashMap<>();
                                            likesMap.put("utc", utc);

                                            firebaseFirestore.collection("TubbePosts")
                                                    .document(posterId)
                                                    .collection("Posts")
                                                    .document(postId).collection("Likes")
                                                    .document(currentUserId).set(likesMap);
                                        }
                                    }
                                }
                            });

                }
            }
        });

        firebaseFirestore.collection("TubbePosts").document(posterId)
                .collection("Posts").document(postId).collection("Comments")
                .addSnapshotListener(new EventListener<QuerySnapshot>() {
                    @Override
                    public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
                        if (queryDocumentSnapshots != null) {
                            if (!queryDocumentSnapshots.isEmpty()) {
                                int count = queryDocumentSnapshots.size();
                                if (count < 1000) {
                                    holder.mCommentCount.setText(count + "");
                                } else {
                                    holder.mCommentCount.setText(getCount(count));
                                }
                            } else {
                                holder.mCommentCount.setText("0");
                            }
                        }
                    }
                });


        holder.mPosterImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!currentUserId.equals(posterId)) {
                    Intent viewIntent = new Intent(context, ViewAccountActivity.class);
                    viewIntent.putExtra("userId", posterId);
                    context.startActivity(viewIntent);
                } else {
                    Toast.makeText(context, context.getResources().getString(R.string.your_account), Toast.LENGTH_SHORT).show();
                   /* AccountFragment accountFragment = new AccountFragment();
                    HomeFragment homeFragment = new HomeFragment();
                    FragmentTransaction fragmentTransaction = homeFragment.getActivity()
                            .getSupportFragmentManager()
                            .beginTransaction();
                    fragmentTransaction.replace(R.id.main_frame, accountFragment);
                    fragmentTransaction.addToBackStack(null);
                    fragmentTransaction.commit(); */
                }
            }
        });

        holder.mCommentBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent commentIntent = new Intent(context, CommentActivity.class);
                commentIntent.putExtra("posterId", posterId);
                commentIntent.putExtra("postId", postId);
                context.startActivity(commentIntent);
            }
        });

        holder.mCard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent viewIntent = new Intent(context, ViewActivity.class);
                viewIntent.putExtra("postId", postId);
                viewIntent.putExtra("posterId", posterId);
                viewIntent.putExtra("desc", descText);
                viewIntent.putExtra("mediaUrl", mediaUrl);
                viewIntent.putExtra("posterImgUrl", img);
                viewIntent.putExtra("format", format);
                viewIntent.putExtra("utc", utc);
                context.startActivity(viewIntent);
            }
        });

    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public int getItemCount() {
    return postList.size();
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

public class ViewHolder extends RecyclerView.ViewHolder {

    private View mView;
    private CardView mCard;
    private ImageView mPostImage, mLikeBtn, mCommentBtn, mPosterImg, mPlay;
    private TextView mDesc, mLikeCount, mCommentCount, mTime;

    public ViewHolder(View itemView) {
        super(itemView);

        mView = itemView;
        mCard = mView.findViewById(R.id.postCard);
        mPostImage = mView.findViewById(R.id.post_img);
        mPosterImg = mView.findViewById(R.id.posterImg);
        mDesc = mView.findViewById(R.id.postDesc);
        mLikeBtn = mView.findViewById(R.id.likeBtn);
        mLikeCount = mView.findViewById(R.id.likesCount);
        mCommentBtn = mView.findViewById(R.id.commentBtn);
        mCommentCount = mView.findViewById(R.id.commentCount);
        mTime = mView.findViewById(R.id.postTime);
        mPlay = mView.findViewById(R.id.play_hint);
    }

    private void setUserImg(String downloadUrl) {
        if (!TextUtils.isEmpty(downloadUrl)) {
            RequestOptions placeholderRequest = new RequestOptions();
            placeholderRequest.placeholder(R.color.grey200);
            Glide.with(context).setDefaultRequestOptions(placeholderRequest).load(downloadUrl).into(mPosterImg);
        }
    }

    private void setImg(String downloadUrl) {
        if (!TextUtils.isEmpty(downloadUrl)) {
            RequestOptions placeholderRequest = new RequestOptions();
            placeholderRequest.placeholder(R.drawable.ic_image);
            Glide.with(context).setDefaultRequestOptions(placeholderRequest).load(downloadUrl).into(mPostImage);
        }
    }

    private void setVideoImg(String downloadUrl) {
        if (!TextUtils.isEmpty(downloadUrl)) {
            long interval = getPosition() * 1000;
            RequestOptions options = new RequestOptions().frame(interval);
            placeholder = new RequestOptions();
            placeholder.placeholder(R.drawable.ic_image);
            Glide.with(context).setDefaultRequestOptions(placeholder).asBitmap()
                    .load(downloadUrl).apply(options).into(mPostImage);
        }
    }
}

我的模特:

public class PostModel extends DocId {

private String descText, postId, mediaUrl, posterId, format;
private Date utc;

public PostModel (){}

public PostModel(String descText, String postId, String mediaUrl, String posterId, String format, Date utc) {
    this.descText = descText;
    this.postId = postId;
    this.mediaUrl = mediaUrl;
    this.posterId = posterId;
    this.format = format;
    this.utc = utc;
}

public String getDescText() {
    return descText;
}

public String getPostId() {
    return postId;
}

public String getMediaUrl() {
    return mediaUrl;
}

public String getPosterId() {
    return posterId;
}

public String getFormat() {
    return format;
}

public Date getUtc() {
    return utc;
}

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

我对.addSnapshotListener的解决方案是在添加文档之前在可变列表中使用clear()

productosLista.clear()
for (doc in documentSnapshots!!) {
    val producto = doc.toObject<Productos>(Productos::class.java)
    productosLista.add(producto)
}

答案 1 :(得分:0)

firestore 数据库 调用数据时,我在 recyclerView 上遇到了同样的数据重复问题。使用 Java 8,它允许人们通过调用 clear() 方法来使用集合接口,如下所示:

listName.clear(); //clears the list
listName.add(new list(a,b)); //update the list with new data
adapter.notifyDataSetChanged(); //updates the data into a recyclerView

此外,如果要查询多个数据以显示在 recyclerView 上,则可以调用 removeIf() 方法:

listName.removeIf(list -> list.getId() = 1); //Removes all of the elements of this collection that satisfy the given predicate.
listName.add(new list(a,b)); //update the list with new data
adapter.notifyDataSetChanged(); //updates the data into a recyclerView

上述方法 clear()removeIf() 完成了在 recyclerView 中避免数据重复的工作。