Повторяются элементы в 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);
}
}
Помогите, пожалуйста