我正在建立一个以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;
我感谢任何帮助。