android / android/architecture-samples

Memory leak in TasksFragment

Open
#714 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Kotlin
Stars
45.8k
Forks
11.9k
PR merge metrics
No merged PRs in 30d

Description

Detected leak path by LeakCanary:
```
┬───
│ GC Root: System class

├─ android.view.inputmethod.InputMethodManager class
│ Leaking: NO (InputMethodManager↓ is not leaking and a class is never leaking)
│ ↓ static InputMethodManager.sInstance
├─ android.view.inputmethod.InputMethodManager instance
│ Leaking: NO (DecorView↓ is not leaking and InputMethodManager is a singleton)
│ ↓ InputMethodManager.mNextServedView
├─ com.android.internal.policy.DecorView instance
│ Leaking: NO (RecyclerView↓ is not leaking and View attached)
│ mContext instance of com.android.internal.policy.DecorContext, wrapping activity com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity with mDestroyed = false
│ Parent android.view.ViewRootImpl not a android.view.View
│ View#mParent is set
│ View#mAttachInfo is not null (view attached)
│ View.mWindowAttachCount = 1
│ ↓ DecorView.mAttachInfo
├─ android.view.View$AttachInfo instance
│ Leaking: NO (RecyclerView↓ is not leaking)
│ ↓ View$AttachInfo.mScrollContainers
├─ java.util.ArrayList instance
│ Leaking: NO (RecyclerView↓ is not leaking)
│ ↓ ArrayList.elementData
├─ java.lang.Object[] array
│ Leaking: NO (RecyclerView↓ is not leaking)
│ ↓ Object[].[1]
├─ androidx.recyclerview.widget.RecyclerView instance
│ Leaking: NO (View attached)
│ mContext instance of com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity with mDestroyed = false
│ View.parent android.widget.LinearLayout attached as well
│ View#mParent is set
│ View#mAttachInfo is not null (view attached)
│ View.mID = R.id.tasks_list
│ View.mWindowAttachCount = 1
│ ↓ RecyclerView.mAdapter
│ ~~~~~~~~
├─ com.example.android.architecture.blueprints.todoapp.tasks.TasksAdapter instance
│ Leaking: UNKNOWN
│ ↓ TasksAdapter.viewModel
│ ~~~~~~~~~
├─ com.example.android.architecture.blueprints.todoapp.tasks.TasksViewModel instance
│ Leaking: UNKNOWN
│ ↓ TasksViewModel._snackbarText
│ ~~~~~~~~~~~~~
├─ androidx.lifecycle.MutableLiveData instance
│ Leaking: UNKNOWN
│ ↓ MutableLiveData.mObservers
│ ~~~~~~~~~~
├─ androidx.arch.core.internal.SafeIterableMap instance
│ Leaking: UNKNOWN
│ ↓ SafeIterableMap.mStart
│ ~~~~~~
├─ androidx.arch.core.internal.SafeIterableMap$Entry instance
│ Leaking: UNKNOWN
│ ↓ SafeIterableMap$Entry.mNext
│ ~~~~~
├─ androidx.arch.core.internal.SafeIterableMap$Entry instance
│ Leaking: UNKNOWN
│ ↓ SafeIterableMap$Entry.mKey
│ ~~~~
├─ com.example.android.architecture.blueprints.todoapp.util.ViewExtKt$setupSnackbar$1 instance
│ Leaking: UNKNOWN
│ Anonymous class implementing androidx.lifecycle.Observer
│ ↓ ViewExtKt$setupSnackbar$1.$this_setupSnackbar
│ ~~~~~~~~~~~~~~~~~~~
╰→ androidx.coordinatorlayout.widget.CoordinatorLayout instance
​ Leaking: YES (ObjectWatcher was watching this because com.example.android.architecture.blueprints.todoapp.tasks.TasksFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
​ key = 080d1590-6d2b-47da-8b64-4be379e522aa
​ watchDurationMillis = 8201
​ retainedDurationMillis = 3178
​ key = 4e988abe-ac80-43b1-8004-e3c84d5d8bcd
​ watchDurationMillis = 8205
​ retainedDurationMillis = 3179
​ mContext instance of com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity with mDestroyed = false
​ View#mParent is null
​ View#mAttachInfo is null (view detached)
​ View.mID = R.id.coordinator_layout
​ View.mWindowAttachCount = 1
```
The reason is that the sample keeps a `lateinit listAdapter` in `TasksFragment`. When we navigate to `AddEditTaskFragment`, the `RecyclerView` destroyed but the adapter is still keep the reference of it which causes the leak.

Do you have any suggestion to fix this?
Thanks!

Contributor guide

Open the contributing guide

Research direction

Start by reading TasksFragment's view lifecycle and its lateinit listAdapter, then trace TasksAdapter.viewModel through TasksViewModel._snackbarText and ViewExtKt.setupSnackbar. Confirm how navigation to AddEditTaskFragment destroys the view. Done means the destroyed TasksFragment views are no longer retained by the adapter or snackbar observer, as verified with the reported LeakCanary path.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.