我正在使用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;
}
感谢您的帮助。
答案 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
中避免数据重复的工作。