Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Ask Question
I want to add new item(s) in a list of RecyclerView and always place it at the very top of the list. But unfortunately strange behavior occurs while updating the list I used getAdapterPosition() to monitor if index/position is getting update.
Default list: 0, 1, 2, 3, 4 is my first list
My Pagination rule is 5 items will be added every time a user scroll at the very bottom.
Now I want to add new item and place it at the top of list without using too much of memory that is why I do not want to use notifyDataSetChanged() at all.
But after adding new item this is the result.
When new item is added: "this is the new item" > 0 , 0, 1, 2, 3, 4
The getAdapterPosition() is not getting update, instead it duplicates the index thus creating a two or more zeros index every time new item is added?
My understanding with notifyItemRangeInserted() is when new item added, it will update the remaining items in the list starting from what we pass in the first parameter of it which is the "positionStart" and update the next/rest of the item right after that positionStart.
This is my first query with Firestore that will get the first 5 items in onCreate method.
//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);
And when a user scroll down and reach the bottom this method will be called to fetched the next 5 items available in database.
//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;
How can I solve this without using notifyDataSetChange() or is it even possible?
Another thing is that when I use notifyItemRangeInserted(0, list.size()); It throws an error:
IndexOutOfBoundsException: Inconsistency detected.
–
–
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.