4

I receive a notice from Leakcanary when debugging my app on a Samsung Galaxy S10 running on Android 12.

Indeed, Leakcanary notifies a leaked activity when toggle from light to night mode or vice versa.

Below is shown the Leakcanary report:

┬───
│ 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.mCurRootView
├─ android.view.ViewRootImpl instance
│    Leaking: NO (DecorView↓ is not leaking)
│    mContext instance of com.android.internal.policy.DecorContext, wrapping
│    activity com.my_package.activity.MainActivity
│    with mDestroyed = false
│    ViewRootImpl#mView is not null
│    mWindowAttributes.mTitle = "com.my_package.activity.MainActivity"
│    mWindowAttributes.type = 1
│    ↓ ViewRootImpl.mParentDecorView
├─ com.android.internal.policy.DecorView instance
│    Leaking: NO (View attached)
│    View is part of a window view hierarchy
│    View.mAttachInfo is not null (view attached)
│    View.mWindowAttachCount = 1
│    mContext instance of com.android.internal.policy.DecorContext, wrapping
│    activity com.my_package.activity.MainActivity
│    with mDestroyed = false
│    ↓ DecorView.mMSActions
│                ~~~~~~~~~~
├─ com.samsung.android.multiwindow.MultiSplitActions instance
│    Leaking: UNKNOWN
│    Retaining 43 B in 1 objects
│    ↓ MultiSplitActions.mWindow
│                        ~~~~~~~
├─ com.android.internal.policy.PhoneWindow instance
│    Leaking: YES (Window#mDestroyed is true)
│    Retaining 15,0 kB in 286 objects
│    mContext instance of com.my_package.activity.
│    MainActivity with mDestroyed = true
│    mOnWindowDismissedCallback instance of com.my_package.activity.MainActivity with mDestroyed = true
│    ↓ Window.mContext
╰→ com.my_package.activity.MainActivity instance
​     Leaking: YES (ObjectWatcher was watching this because com.my_package.activity.MainActivity received
​     Activity#onDestroy() callback and Activity#mDestroyed is true)
​     Retaining 534,5 kB in 11484 objects
​     key = 442fa647-742b-4e2f-b4c7-452ea418ffdb
​     watchDurationMillis = 5868
​     retainedDurationMillis = 867
​     dataBackupAgent instance of com.my_package.activity.
​     MyBackupAgent
​     mApplication instance of com.my_package.activity.MyApplicationClass
​     mBase instance of androidx.appcompat.view.ContextThemeWrapper

METADATA

Build.VERSION.SDK_INT: 31
Build.MANUFACTURER: samsung
LeakCanary version: 2.8.1
Stats: LruCache[maxSize=3000,hits=129558,misses=253658,hitRate=33%]
RandomAccess[bytes=21184127,reads=253658,travel=102525154060,range=50140315,size
=69790586]
Analysis duration: 12217 ms

Please do you have any idea concerning the origin of this ?

First of all thank you for your reply.

Indeed, I have a class named MyBackupAgent:

@Singleton
class MyBackupAgent @Inject constructor(
    private val backupPrefsKey: String,
    private val backupHelper: MyBackupHelper
): BackupAgentHelper() {

    override fun onCreate() {
        super.onCreate()
        addHelper(backupPrefsKey, backupHelper)
    }

}

The MyBackupHelper class has the following implementation:

@Singleton
class MyBackupHelper @Inject constructor(
    private val context: Context,
    private val backupPreferencesKey: String
) : SharedPreferencesBackupHelper(context, backupPreferencesKey) {
     .....
}

The MyBackupAgent is injected into Activity with:

@Inject
lateinit var backupAgent: MyBackupAgent

The MyBackupAgent and MyBackupHelper are provided by the MyBaseModule class:

@InstallIn(SingletonComponent::class)
@Module
class MyBaseModule {

    @Singleton
    @Provides
    fun provideMyBackupHelper(@ApplicationContext context: Context, @BackUpPreferencesKey backupPrefsKey: String): MyBackupHelper {
        val backupHelper by lazy {
            MyBackupHelper(context, backupPrefsKey)
        }
        return backupHelper
    }

    @Singleton
    @Provides
    fun provideMyBackupAgent(@BackUpPreferencesKey backupPreferencesKey: String, backupHelper: MyBackupHelper): MyBackupAgent {
        val backupAgent by lazy {
            MyBackupAgent(backupPreferencesKey, backupHelper)
        }
        return backupAgent
    }

}
  • Do u have a class named `MyBackupAgent` ? – ADM Jan 28 '22 at 05:55
  • Hi ADM, I add some clarification in an answer below. – andronaline Jan 28 '22 at 09:46
  • Do not add your code as answer instead you can edit your question . i have edited it for now you can remove the below answer of yours. – ADM Jan 28 '22 at 09:50
  • As per stack trace you are passing `MainActivity` instance to `MyBackupAgent` Somehow which i can not see in your code and thats what causing the leak . Can you check this once if you are passing Activity's instance to any of these classes `MyBackupAgent` or `MyBackupHelper`? – ADM Jan 28 '22 at 10:24
  • Thanks very much @ADM, no more leak! – andronaline Jan 28 '22 at 15:30
  • I have almost exactly the same leak except without the line `dataBackupAgent instance of com.my_package.activity.MyBackupAgent` Any ideas? – Mark Jul 26 '22 at 02:23

0 Answers0