Skip to content

Optimize RecyclerView performance after returning from NoteEditActivity (scroll position, lag, unnecessary re-rendering) #208

Description

@amarradi

📝 Description

When returning from NoteEditActivity to MainActivity, the app currently reloads the entire note list, resulting in a noticeable jump (especially in GridView layout) and UI lag before the list becomes usable. This negatively impacts user experience, particularly with many notes or when the ReleaseNote header is visible.

🔍 Observed behavior

  • After closing NoteEditActivity, noteViewModel.loadNotes() is called in MainActivity.
  • This triggers the observer for notesLiveData, which in turn calls noteAdapter.updateNotes(...).
  • That invokes DiffUtil.calculateDiff(...) internally, causing the entire adapter content to be recalculated.
  • Then, recyclerView.scrollToPosition(...) is called to restore the previous scroll position.
  • This entire sequence happens on the UI thread, leading to stuttering and visible jumping.
  • With StaggeredGridLayoutManager, layouting is especially expensive.

⚠️ Root cause

  • loadNotes() always loads the full note list, even when only one note was edited or created.
  • This causes a full rebind in the adapter, triggering layout invalidation.
  • Scroll restoration occurs too early, before RecyclerView has finished layouting.
  • The ReleaseNote header is reset on every return, even if unchanged → triggers layout recalculation.

✅ Expected behavior

  • Only update the changed or new note in the list (e.g., via updateSingleNote(...)).
  • Avoid full list reload unless necessary.
  • Restore scroll position only after RecyclerView layout is complete, ideally without expensive ViewTreeObserver.
  • Only update the ReleaseNote header if its content actually changed.

✅ Suggested solution (for next version)

1. Add updateSingleNote(Note note) method in NoteViewModel

  • Replaces the matching note in the notesLiveData list.
  • Triggers a minimal update via setValue().

2. In NoteEditActivity

  • Add the updated note to the result Intent:
    intent.putExtra("updated_note", note);
    setResult(RESULT_OK, intent);

3. In MainActivity

  • Handle the updated note in ActivityResultLauncher:
    if (result.getResultCode() == RESULT_OK) {
        Intent data = result.getData();
        if (data != null && data.hasExtra("updated_note")) {
            Note updated = data.getParcelableExtra("updated_note");
            noteViewModel.updateSingleNote(updated);
            scrollAfterLoadToPosition = lastScrollPosition;
        }
    }
  • Do not call loadNotes() after every return unless absolutely necessary (e.g., delete or category switch).

4. Restore scroll position using recyclerView.post(...), only if scrollAfterLoadToPosition >= 0.

5. Prevent unnecessary ReleaseNote updates

if (!releaseNote.equals(noteAdapter.getReleaseNote())) {
    noteAdapter.setReleaseNoteHeader(releaseNote);
}

🛠 To-do list

  • Add updateSingleNote(...) method to NoteViewModel
  • Return updated_note from NoteEditActivity using Intent.putExtra
  • In MainActivity, avoid loadNotes() after return and use the new update method instead
  • Move scroll restoration logic into the notesLiveData observer
  • Add check to avoid resetting the ReleaseNote header if it's unchanged
  • Optionally, also improve onReleaseNoteClosed() to avoid unnecessary reloads

🕓 Timing

This optimization is scheduled for a future release to allow a clean and well-tested implementation.

🧩 Affected components

  • MainActivity.java
  • NoteViewModel.java
  • NoteEditActivity.java
  • NoteAdapter.java

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions