我想在RecyclerView列表中添加新项目,并始终将其放在列表的最顶端。但不幸的是,在更新我使用getAdapterPosition()监视索引/位置是否得到更新的列表时,出现了奇怪的行为。
默认列表:0、1、2、3、4是我的第一个列表
我的分页规则是,每次用户在最底部滚动时,都会添加5个项目。
现在,我想添加新项并将其放在列表的顶部,而不使用太多内存,这就是为什么我根本不想使用notifyDataSetChanged()。
但在添加新项目后,这就是结果。
添加新项目时:“这是新项目”>0 , 0, 1, 2, 3, 4
getAdapterPosition()没有得到更新,而是复制索引,从而在每次添加新项时创建一个两个或多个零的索引?
我对notifyItemRangeInserted()的理解是,当添加新项目时,它将更新列表中的剩余项目,从我们传入的第一个参数“positionStart”开始,并在positionStart之后更新项目的下一个/其余部分。
这是我第一次使用Firestore进行查询,它将在onCreate方法中获取前5项。
//Load the first item(s) to display
//Set a query according to time in milliseconds
mQuery = mDatabase.collection("Announcements")
.orderBy("time", Query.Direction.DESCENDING)
.limit(5);
//Getting all documents under Announcement collection with query's condition
annon_listener = mQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(final QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
//If something went wrong
if (e != null)
Log.w(TAG, "Listen failed.", e);
//If any post exist put it to model and add it to List to populate the CardView
//If data exist in the first 5 items then item should be loaded making our 'isFirstListLoaded' variable to be true
if (!documentSnapshots.isEmpty()){
//If first item are loaded then every update post should be on the top not at the bottom
//This can only be called once to avoid confusion/duplication getting new item
if (isFirstListLoaded){
//Get the documents of last item listed in our RecyclerView
mLastSeen = documentSnapshots.getDocuments().get(documentSnapshots.size()-1);
//Clear the list first to get a latest data
announcementList.clear();
}
//Loop to read each document
for (DocumentChange doc : documentSnapshots.getDocumentChanges()){
//Only added document will be read
switch (doc.getType()){
case ADDED:
//Call the model to populate it with document
AnnouncementModel annonPost = doc.getDocument().toObject(AnnouncementModel.class)
.withId(doc.getDocument().getId());
//To retrieve all post data in the same time we need to place this if else over here
//So user data and his/her post will be retrieve at the same time
//This can only be called once to avoid confusion getting new item(s)
if (isFirstListLoaded){
announcementList.add(annonPost);
announcementRecyclerAdapter.notifyDataSetChanged();
}
if (isJustDelete)
isJustDelete = false;
//If someone just remove a post then do nothing and return the state to false
//This will be called once a user added new item to database and put it to top of the list
else if (!isFirstListLoaded && !isJustDelete){
//Before adding new item to the list lets save the previous size of the list as a reference
int prevSize = announcementList.size();
//This will be called only if user added some new post
announcementList.add(0, annonPost);
//Update the Recycler adapter that new data is added
announcementRecyclerAdapter.notifyItemRangeInserted(0, announcementList.size() - prevSize);
}
//Just checking of where's the data fetched from
String source = documentSnapshots.getMetadata().isFromCache() ?
"Local" : "Server";
Log.d(TAG, "Data fetched from " + source + "\n" + doc.getDocument().getData());
break;
}
}
//After the first item/latest post was loaded set it to
false it means that first items are already fetched
isFirstListLoaded = false;
}
//If no post exist then display no content TextView
else if (announcementList.isEmpty()){
noContent.setVisibility(View.VISIBLE);
annonRecyclerView.setVisibility(View.GONE);
}
当用户向下滚动并到达底部时,将调用此方法获取数据库中接下来的5个可用项。
//Load more queries
private void loadMoreList(){
//Load the next item(s) to display
//Set a query according to time in milliseconds
//This time start getting data AFTER the last item(s) loaded
mQuery = mDatabase.collection("Announcements")
.orderBy("time", Query.Direction.DESCENDING)
.startAfter(mLastSeen)
.limit(5);
//Getting all documents under Announcement collection with query's condition
annon_listener = mQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(final QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
//If something went wrong
if (e != null)
Log.w(TAG, "Listen failed.", e);
//If no more item(s) to load
if (documentSnapshots.isEmpty()){
isFullyLoaded = true;
messenger = Snackbar.make(mPullToRefreshView,"No more item(s) to load.",Snackbar.LENGTH_LONG)
.setActionTextColor(Color.WHITE)
.setAction("Dismiss", new View.OnClickListener() {
@Override
public void onClick(View v) {
messenger.dismiss();
}
});
messenger.show();
}
else{
//If more data exist then update our 'mLastSeen' data
//Update the last list shown in our RecyclerView
mLastSeen = documentSnapshots.getDocuments().get(documentSnapshots.size()-1);
//Loop to read each document
for (DocumentChange doc : documentSnapshots.getDocumentChanges()){
//Only added document will be read
switch (doc.getType()){
case ADDED:
//Call the model to repopulate it with document
AnnouncementModel annonPost = doc.getDocument().toObject(AnnouncementModel.class)
.withId(doc.getDocument().getId());
//This if condition is use to avoid rumbling the item position when deleting some item
if (isJustDelete)
isJustDelete = false;
else if (!isJustDelete && !isFullyLoaded){
int prevSize = announcementList.size();
//Add any new item(s) to the List
announcementList.add(announcementList.size(), annonPost);
//Update the Recycler adapter that new data is added
//This trick performs recycling even though we set nested scroll to false
announcementRecyclerAdapter.notifyItemRangeInserted(announcementList.size(), announcementList.size() - prevSize);
}
//Just checking of where's the data fetched from
String source = documentSnapshots.getMetadata().isFromCache() ?
"Local" : "Server";
Log.d(TAG, "Data fetched from " + source + "\n" + doc.getDocument().getData());
break;
case REMOVED:
break;
case MODIFIED:
break;
}
}
}
}
});
如果不使用notifyDataSetChange(),我如何解决这个问题,或者这是否可能?
另一件事是,当我使用notifyItemRangeInserted(0,list.size())时;它抛出一个错误:
IndexOutOfBoundsException:检测到不一致。