添加或删除数据时重复的RecyclerView项目 Firebase Firestore

1 人关注

我正在建立一个以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;

我感谢任何帮助。

4 个评论
如果你遇到了问题,最好是创建一个 MCVE 发表问题时。你的帖子几乎 500 这个问题的代码行数。这对人们来说是非常多的,可以在网上进行解析和尝试调试。请编辑你的问题,只保留相关代码。
同时,你可以看一下我的答案,从 this 在这篇文章中,我解释了如何通过结合查询游标和 limit() 方法来分页查询Firestore。我也可以看一下这个 video 以便更好地理解。
谢谢,但我需要实时检索数据,不需要.get()。
在这种情况下,你需要使用 addSnapshotListener 。这几乎是同样的事情。
android
firebase
listview
android-recyclerview
google-cloud-firestore
Geek Dev
Geek Dev
发布于 2019-01-11
2 个回答
4xMafole
4xMafole
发布于 2020-01-30
已采纳
0 人赞同

在从 recyclerView 中调用数据时,我也遇到了数据重复的问题。 Firestore数据库 . Using 爪哇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

Gaston Fassi Lavalle
Gaston Fassi Lavalle
发布于 2020-01-30
0 人赞同

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

productosLista.clear()