10

For some reason, when adding a new item to the RecyclerView (should be inserted to the top of the list), it won't show up unless I scroll down the list and back up to the top, and without any animation either. (Just appears at the top of the list as if it was there the whole time). Removing an item works fine with the proper animations.

RecyclerViewAdapter:

@Override
public void onNewDatabaseEntryAdded() {
    //item added to top of the list
    notifyItemInserted(0);
}

public FileViewerAdapter(Context context) {
    super();
    mContext = context;
    mDatabase = new DBHelper(mContext);
    mDatabase.setOnDatabaseChangedListener(this);
}

SQLite Database:

private static OnDatabaseChangedListener mOnDatabaseChangedListener;

public static void setOnDatabaseChangedListener(OnDatabaseChangedListener listener) {
    mOnDatabaseChangedListener = listener;
}

public long addRecording(String recordingName, String filePath, long length) {

    SQLiteDatabase db = getWritableDatabase();
    ContentValues cv = new ContentValues();
    cv.put(DBHelperItem.COLUMN_NAME_RECORDING_NAME, recordingName);
    cv.put(DBHelperItem.COLUMN_NAME_RECORDING_FILE_PATH, filePath);
    cv.put(DBHelperItem.COLUMN_NAME_RECORDING_LENGTH, length);
    cv.put(DBHelperItem.COLUMN_NAME_TIME_ADDED, System.currentTimeMillis());
    long rowId = db.insert(DBHelperItem.TABLE_NAME, null, cv);

    if (mOnDatabaseChangedListener != null) {
        mOnDatabaseChangedListener.onNewDatabaseEntryAdded();
    }

    return rowId;
}

Listener:

public interface OnDatabaseChangedListener{
    void onNewDatabaseEntryAdded();
    void onDatabaseEntryRenamed();
}

edit:

I should mention that if I use NotifyDataSetChanged instead of NotifyItemInserted, then the new item shows up immediately, but the RecyclerView will not scroll to the top of the list. (Manually have to scroll up to see it).

Daniel Kim
  • 267
  • 3
  • 16
  • to add a new item to the RecyclerView at the position 0 and animate it nicely you have to: add new item to your adapter and then postpone smoothscrolling. Like this: recyclerAdapter.add(position, item); recyclerAdapter.notifyItemInserted(position); new Handler().postDelayed(() -> recyclerView.smoothScrollToPosition(position), 200); (here I used lambda expression). Don't forget to add your custom LinearLayoutManager to your recyclerView with overriden smoothScrollToPosition method. (here is how to do it: https://stackoverflow.com/a/36227740/5502121) – Kirill Karmazin Jul 30 '18 at 14:58

2 Answers2

17

This is happening because LinearLayoutManager thinks the item is inserted above the first item. This behavior makes sense when you are not at the top of the list but I understand that it is unintuitive when you are at the top of the list. We may change this behavior, meanwhile, you can call linearLayoutManager.scrollToPosition(0) after inserting the item if linearLayoutManager.findFirstCompletelyVisibleItemPosition() returns 0.

M. Reza Nasirloo
  • 16,434
  • 2
  • 29
  • 41
yigit
  • 37,683
  • 13
  • 72
  • 58
  • I'm calling addRecording from inside a Service (after MediaRecorder finishes capturing audio), so I'm not sure of the way I would call lm.scrollToPosition from the fragment :/ – Daniel Kim Jan 04 '15 at 02:45
  • actually i got that part above! the problem is, i did setReverseLayout(true) and setStackFromEnd(true) when creating the RecyclerView, so calling lm.scrollToPosition(0) brings me to the BOTTOM of the view.. any way to fix this? Maybe this is also why notifyItemInserted(0) is also not animating? However, notifyItemRemoved(position) works flawlessly.. and the RecyclerView.ViewHolder correctly shows the top as position 0 when clicking on an item. – Daniel Kim Jan 04 '15 at 02:55
  • edit: got it to work by setting position to getItemCount() - 1, oddly enough.. still not animated though :/ (sorry for continuous comments, stackoverflow not allowing me to edit) – Daniel Kim Jan 04 '15 at 03:04
  • Setting both reverse layout and stack from end seems odd. What is your use case? Also, you should be calling scroll to position right after you add the item. Otherwise, it may not animate (depends if next layout traversal comes between the two calls or not). – yigit Jan 04 '15 at 03:17
  • when using reverse layout, it got the order right but started stacking from the bottom of the screen, so I had to also set stack from end to be true (end being the top of the screen), to make the list start from the top. i realized that it's probably not animating because the item is added while I am in another fragment (to record audio). I wish there is a way to make it animate the first time I switch to the file viewer fragment after saving the file to the database. – Daniel Kim Jan 04 '15 at 03:23
  • Oh yea, if RV was detached, it won't create animations. You can post a message to the RV fragment and handle it when it is visible (both insert and notify when handling the message). – yigit Jan 04 '15 at 03:33
  • @yigit I am having similar issue.... my item is big enough and it shows one item at a time on the screen. I am adding to the bottom of recyclerView. It is showing animation (I can see it partly) but item is not visible as it is not pushed up on the screen. What could be issue? It s happening for all position. But interestingly, if i put notifyItemInserted position hardcoded 1 it works well. I am doing it notifyItemInserted(dataset.size +1) it doesn't work – user2095470 Jan 21 '16 at 07:23
  • `notifyItemInserted(dataset.size)` should be correct index. Also, you need to call `scrollToPosition(newlyAddedItemIndex)` to see it. – yigit Jan 21 '16 at 23:13
3

I fix it using notifyItemChange first item. Just like this:

((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(0, 0);
adapter.notifyItemChanged(0);
chenupt
  • 1,781
  • 1
  • 14
  • 13