Повторяются элементы в Recycler View, а также подвисание при скроллинге

При скролинг Recycler View подвисает, а также в нём дублируются ранее добавленные элементы.

Код адаптера:

public class NewNewsAdapter extends RecyclerView.Adapter {

public static int NORMAL = 1;

DatabaseReference likeReference;
DatabaseReference postsReference;
DatabaseReference usersReference;

FirebaseAuth mAuth;

String userId;

List<Posts> posts;

Context context;

public NewNewsAdapter(Context context) {
    this.posts = new ArrayList<>();
    this.context = context;
}

/**
 * Add and update data in recycler view.
 *
 * @param postsNew
 */
public void addAllData(List<Posts> postsNew) {
    int initSize = posts.size();

    posts.addAll(postsNew);

    notifyItemRangeChanged(initSize, postsNew.size());
}

/**
 * ViewHolder Create
 *
 * @param parent
 * @param viewType
 * @return
 */
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    likeReference = FirebaseDatabase.getInstance().getReference().child("likes");
    postsReference = FirebaseDatabase.getInstance().getReference().child("posts");
    usersReference = FirebaseDatabase.getInstance().getReference().child("users");

    mAuth = FirebaseAuth.getInstance();
    userId = mAuth.getCurrentUser().getUid();

    View view = inflater.inflate(R.layout.post_template, parent, false);
    return new PostDefaultViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    bindDefaultPost(holder, position);
}

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

/**
 * Binding default post
 * @param holder
 * @param position
 */
private void bindDefaultPost(RecyclerView.ViewHolder holder, int position) {
    final PostDefaultViewHolder postHolder = (PostDefaultViewHolder) holder;

    // post id
    final String postId = posts.get(position).getPostId();

    if (postId != null) {

        String[] postIdDecrypt = postId.split("_");

        if (postIdDecrypt.length == 3)
        {
            Log.e("NewsAdapter", "PID: " + postId);

            /**
             * Add image
             */
            Glide.with(context).load(posts.get(position).getImage()).into(postHolder.image);

            /**
             * Add tags to ChipGroup
             */
            String tagsData = posts.get(position).getTags();
            String[] tags = tagsData.split(", ");

            if (postHolder.tags.getChildCount() == 0)
            {
                for (String tag : tags) {
                    View view = LayoutInflater.from(context).inflate(R.layout.tags_template, postHolder.tags, false);
                    Chip tagTmp = view.findViewById(R.id.chip6);
                    tagTmp.setText(tag);
                    postHolder.tags.addView(tagTmp);
                }
            }

            /**
             * Post Text
             */
            postHolder.text.setText(posts.get(position).getText());

            /**
             * Add date to "User info and date TextView"
             */
            Date date = new java.util.Date(Long.parseLong(posts.get(position).getDate())*1000L);

            SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("dd.MM.yyyy ");
            dateFormat.setTimeZone(TimeZone.getDefault());
            String dateStr = dateFormat.format(date);

            SimpleDateFormat timeFormat = new java.text.SimpleDateFormat(" HH:mm");
            timeFormat.setTimeZone(TimeZone.getDefault());
            String timeStr = timeFormat.format(date);

            String publishDate = dateStr + context.getString(R.string.in) + timeStr;

            postHolder.postData_username_time.setText(publishDate + " • ");

            /**
             * Add data from usersDatabase
             */
            usersReference.child(posts.get(position).getAuthorId()).addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    User user = snapshot.getValue(User.class);

                    String accountName = user.getAccountName();
                    String avatarUrl = user.getAvatarUrl();
                    String verifyStatus = user.getVerifyStatus();

                    // update data in user and date info
                    postHolder.postData_username_time.setText(postHolder.postData_username_time.getText() + accountName);

                    // set up avatar
                    if (!avatarUrl.equals("none")) {
                        Glide.with(context).load(context).into(postHolder.avatar);
                    }

                    // check for verify status
                    if (!verifyStatus.equals("none")) {
                        postHolder.userVerify.setVisibility(View.GONE);
                    }

                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    Log.e("NewsAdapter/Users", "FirebaseError: " + error);
                }
            });

            /**
             * Add data from likesDatabase
             */

            postHolder.like.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    likeReference.child(postId).addValueEventListener(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot snapshot) {
                            DatabaseReference likeCountReference = postsReference.child(postId).child("likesCount");

                            if (snapshot.hasChild(userId)) {
                                // already liked
                                likeCountReference.runTransaction(new Transaction.Handler() {
                                    @NonNull
                                    @Override
                                    public Transaction.Result doTransaction(@NonNull MutableData currentData) {

                                        Integer likesCount = currentData.getValue(Integer.class);

                                        if (likesCount == null) {
                                            currentData.setValue(0);
                                        } else {
                                            currentData.setValue(likesCount - 1);
                                        }

                                        return Transaction.success(currentData);
                                    }

                                    @Override
                                    public void onComplete(@Nullable DatabaseError error, boolean committed, @Nullable DataSnapshot currentData) {
                                        postHolder.likeCount.setText(String.valueOf(currentData.getValue(Long.class)));
                                    }
                                });
                                likeReference.child(postId).child(userId).removeValue();
                                postHolder.like.setImageResource(R.drawable.ic_likes);
                                postHolder.likeCount.setTextColor(Color.parseColor("#A3A3A3"));
                            } else {
                                // not liked
                                likeCountReference.runTransaction(new Transaction.Handler() {
                                    @NonNull
                                    @Override
                                    public Transaction.Result doTransaction(@NonNull MutableData currentData) {

                                        Integer likesCount = currentData.getValue(Integer.class);

                                        if (likesCount == null) {
                                            currentData.setValue(1);
                                        } else {
                                            currentData.setValue(likesCount + 1);
                                        }

                                        return Transaction.success(currentData);
                                    }

                                    @Override
                                    public void onComplete(@Nullable DatabaseError error, boolean committed, @Nullable DataSnapshot currentData) {
                                        postHolder.likeCount.setText(String.valueOf(currentData.getValue(Long.class)));
                                    }
                                });
                                likeReference.child(postId).child(userId).setValue("+");
                                postHolder.like.setImageResource(R.drawable.ic_liked);
                                postHolder.likeCount.setTextColor(Color.parseColor("#FF7C7C"));
                            }
                        }

                        @Override
                        public void onCancelled(@NonNull DatabaseError error) {
                            Log.e("NewsAdapter/Likes", "FirebaseError: " + error);
                        }
                    });
                }
            });
        }
    }

}

@Override
public int getItemCount() {
    if (posts == null) {
        posts = new ArrayList<>();
    }
    return posts.size();
}

}

Код фрагмента, где добавляются данные:

public class AllNewsFragment extends Fragment {

public static AllNewsFragment newInstance() {
    return new AllNewsFragment();
}

final int ITEM_COUNT = 2;
int total_item = 0, last_visible_item;
boolean isLoading = false, isMaxData = false;

String currentUserID, last_node = "", last_key = "", last_post_first_id = "no";

SharedPreferences sharedPref;
FirebaseAuth mAuth;
DatabaseReference reference;
ArrayList<Posts> posts;

NewNewsAdapter newNewsAdapter;

RecyclerView feed;

TextView postNoFound;

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.all_news_fragment, container, false);
    feed = rootView.findViewById(R.id.all_news);
    postNoFound = rootView.findViewById(R.id.noPostFoundText);
    sharedPref = getActivity().getSharedPreferences("TempData", Context.MODE_PRIVATE);

    mAuth = FirebaseAuth.getInstance();
    currentUserID = mAuth.getCurrentUser().getUid();
    reference = FirebaseDatabase.getInstance().getReference();

    Query query = reference.child("posts")
            .orderByKey()
            .limitToLast(1);

    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            for (DataSnapshot data : snapshot.getChildren())
                last_key = data.getKey();
                SharedPreferences.Editor editor = sharedPref.edit();
                editor.putString("last_key", last_key);
                editor.apply();
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            Log.e("Feed/2", error.getMessage());
        }
    });

    sharedPref.getString("last_key", null);

    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
    linearLayoutManager.setReverseLayout(true);
    linearLayoutManager.setStackFromEnd(true);
    feed.setLayoutManager(linearLayoutManager);
    feed.setItemViewCacheSize(total_item);
    feed.setDrawingCacheEnabled(true);
    feed.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

    newNewsAdapter = new NewNewsAdapter(getActivity().getApplicationContext());
    feed.setAdapter(newNewsAdapter);

    readPosts();

    feed.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            total_item = linearLayoutManager.getItemCount();
            last_visible_item = linearLayoutManager.findLastVisibleItemPosition();

            if (!isLoading && total_item <= ((last_visible_item + ITEM_COUNT)))
            {
                readPosts();
                isLoading = true;
            }
        }
    });

    return rootView;
}


private void readPosts()
{
    posts = new ArrayList<>();
    
    if (!isMaxData) {
        Query query;

        if (TextUtils.isEmpty(last_node)) query = reference.child("posts")
                .orderByKey()
                .limitToFirst(ITEM_COUNT);
        else query = reference.child("posts")
                .orderByKey()
                .startAt(last_node)
                .limitToFirst(ITEM_COUNT);

        query.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if (snapshot.hasChildren())
                {
                    ArrayList<Posts> newPosts = new ArrayList<>();
                    for (DataSnapshot userSnapshot : snapshot.getChildren())
                    {
                        for (DataSnapshot postSnapshot : userSnapshot.getChildren())
                        {
                            String text = postSnapshot.child("text").getValue(String.class);
                            String aId = postSnapshot.child("authorId").getValue(String.class);
                            String date = postSnapshot.child("date").getValue(String.class);
                            String tags = postSnapshot.child("tags").getValue(String.class);
                            String image = postSnapshot.child("image").getValue(String.class);

                            newPosts.add(new Posts(text, tags, image, aId, date, postSnapshot.getKey(), null));
                        }

                    }

                    Log.e("Feed/2", String.valueOf(newPosts.size()));

                    last_node = newPosts.get(newPosts.size() - 1).getPostId();

                    if (!last_node.equals(last_key))
                        newPosts.remove(newPosts.size() - 1);
                    else
                        last_node = "end";

                    newNewsAdapter.notifyDataSetChanged();
                    newNewsAdapter.addAllData(newPosts);

                    last_post_first_id = newPosts.get(0).getPostId();
                } else {
                    isLoading = false;
                    isMaxData = true;
                }

                SharedPreferences.Editor editor = sharedPref.edit();
                editor.putString("last_node", last_node);
                editor.putString("last_first_post_id", last_post_first_id);
                editor.apply();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                isLoading = false;
                Log.e("Feed/2", error.getMessage());
            }
        });
    }

    last_node = sharedPref.getString("last_node", null);
    last_post_first_id = sharedPref.getString("last_first_post_id", null);
}
}

Код ViewHolder:

public class PostDefaultViewHolder extends RecyclerView.ViewHolder {
    public final TextView postData_username_time;
    public final TextView text;
    public final TextView likeCount;
    public final TextView commentCount;
    public final ChipGroup tags;
    public final ImageView image;
    public final ImageView fav;
    public final ImageView report;
    public final ImageView like;
    public final ImageView comments;
    public final ImageView userVerify;
    public final CircleImageView avatar;

    public PostDefaultViewHolder(@NonNull View itemView) {
        super(itemView);

        postData_username_time = itemView.findViewById(R.id.postAuthorInfo_tmp1);
        text = itemView.findViewById(R.id.postText_tmp1);
        likeCount = itemView.findViewById(R.id.postLikeText_tmp1);
        commentCount = itemView.findViewById(R.id.postCommentsText_tmp1);
        tags = itemView.findViewById(R.id.tagsGroup_tmp1);
        image = itemView.findViewById(R.id.postImage_tmp1);
        fav = itemView.findViewById(R.id.postFavBtn_tmp1);
        report = itemView.findViewById(R.id.postReportBtn_tmp1);
        like = itemView.findViewById(R.id.postLike_tmp1);
        comments = itemView.findViewById(R.id.postComments_button_tmp1);
        userVerify = itemView.findViewById(R.id.postAuthorVerifyStatus_tmp1);
        avatar = itemView.findViewById(R.id.postAuthorAvatar_tmp1);
    }
}

Помогите, пожалуйста


Ответы (0 шт):