Я хочу добавить новый элемент (ы) в список RecyclerView и всегда размещать его в самом верху списка. Но, к сожалению, странное поведение происходит при обновлении списка, который я использовал getAdapterPosition (), чтобы отслеживать, обновляется ли индекс / позиция.
Список по умолчанию: 0, 1, 2, 3, 4 - мой первый список
Мое правило разбиения на страницы: 5 пунктов будут добавляться каждый раз, когда пользователь прокручивает в самом низу.
Теперь я хочу добавить новый элемент и поместить его в начало списка, не используя слишком много памяти, поэтому я вообще не хочу использовать notifyDataSetChanged ().
Но после добавления нового предмета это результат.
При добавлении нового элемента: «это новый элемент»> 0, 0, 1, 2, 3, 4
GetAdapterPosition () не получает обновления, вместо этого он дублирует индекс, создавая индекс из двух или более нулей при каждом добавлении нового элемента?
Насколько я понимаю с notifyItemRangeInserted (), когда добавляется новый элемент, он обновляет оставшиеся элементы в списке, начиная с того, что мы передаем в первом его параметре, который является "positionStart", и обновляет следующий / оставшийся элемент сразу после этой позиции.
Это мой первый запрос с Firestore, который получит первые 5 элементов в методе onCreate.
//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: обнаружено несоответствие.