I have a MediaControllerCompat
which is created an instance when a MediaSession
connection is established. When this connection is accomplished I create the MediaControllerCompat
following way:
MediaControllerCompat mediaController = new MediaControllerCompat(this, token);
MediaControllerCompat.setMediaController(this, mediaController);
The token is acquire from MediaSession
.
All the times that back button is pressed a leak is detected. I don't have any callback/listener registered to MediaControllerCompat
. I already tried set MediaController
to null on activity's onDestroy()
method, no success.
MediaControllerCompat.setMediaController(this, null);
Follow bellow the LeakCanary log.
D/LeakCanary: * com.me.PlaybackFullscreenActivity has leaked:
D/LeakCanary: * GC ROOT android.os.ResultReceiver$MyResultReceiver.this$0
D/LeakCanary: * references android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi21$1.this$0 (anonymous subclass of android.os.ResultReceiver)
D/LeakCanary: * references android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi23.mControllerObj
D/LeakCanary: * references android.media.session.MediaController.mContext
D/LeakCanary: * leaks com.me.ui.playback.PlaybackFullscreenActivity instance
D/LeakCanary: * Retaining: 54 KB.
D/LeakCanary: * Reference Key: 004ed9cd-c668-4d23-9ee6-cecad1b980a5
D/LeakCanary: * Device: unknown Android Android SDK built for x86_64 sdk_google_phone_x86_64
D/LeakCanary: * Android Version: 7.1 API: 25 LeakCanary: 1.5 00f37f5
D/LeakCanary: * Durations: watch=5018ms, gc=115ms, heap dump=1936ms, analysis=6011ms
D/LeakCanary: * Details:
D/LeakCanary: * Instance of android.os.ResultReceiver$MyResultReceiver
D/LeakCanary: | this$0 = android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi21$1@322318080 (0x13362f00)
D/LeakCanary: | mDescriptor = java.lang.String@1887101392 (0x707ae1d0)
D/LeakCanary: | mObject = -813433536
D/LeakCanary: | mOwner = android.os.ResultReceiver$MyResultReceiver@322318176 (0x13362f60)
D/LeakCanary: | shadow$_klass_ = android.os.ResultReceiver$MyResultReceiver
D/LeakCanary: | shadow$_monitor_ = 0
D/LeakCanary: * Instance of android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi21$1
D/LeakCanary: | this$0 = android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi23@322317952 (0x13362e80)
D/LeakCanary: | mHandler = android.os.Handler@322318144 (0x13362f40)
D/LeakCanary: | mLocal = true
D/LeakCanary: | mReceiver = android.os.ResultReceiver$MyResultReceiver@322318176 (0x13362f60)
D/LeakCanary: | shadow$_klass_ = android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi21$1
D/LeakCanary: | shadow$_monitor_ = 0
D/LeakCanary: * Instance of android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi23
D/LeakCanary: | mCallbackMap = java.util.HashMap@322587040 (0x133a49a0)
D/LeakCanary: | mControllerObj = android.media.session.MediaController@322587088 (0x133a49d0)
D/LeakCanary: | mExtraBinder = android.support.v4.media.session.MediaSessionCompat$MediaSessionImplApi21$ExtraSession@319823424 (0x13101e40)
D/LeakCanary: | mPendingCallbacks = null
D/LeakCanary: | shadow$_klass_ = android.support.v4.media.session.MediaControllerCompat$MediaControllerImplApi23
D/LeakCanary: | shadow$_monitor_ = 0
D/LeakCanary: * Instance of android.media.session.MediaController
D/LeakCanary: | static MSG_UPDATE_EXTRAS = 7
D/LeakCanary: | static MSG_DESTROYED = 8
D/LeakCanary: | static MSG_UPDATE_VOLUME = 4
D/LeakCanary: | static MSG_UPDATE_QUEUE_TITLE = 6
D/LeakCanary: | static MSG_UPDATE_PLAYBACK_STATE = 2
D/LeakCanary: | static $staticOverhead = byte[72]@317243393 (0x12e8c001)
D/LeakCanary: | static MSG_UPDATE_QUEUE = 5
D/LeakCanary: | static MSG_EVENT = 1
D/LeakCanary: | static TAG = java.lang.String@1886292312 (0x706e8958)
D/LeakCanary: | static MSG_UPDATE_METADATA = 3
D/LeakCanary: | mCallbacks = java.util.ArrayList@322318048 (0x13362ee0)
D/LeakCanary: | mCbRegistered = false
D/LeakCanary: | mCbStub = android.media.session.MediaController$CallbackStub@322317984 (0x13362ea0)
D/LeakCanary: | mContext = com.me.ui.playback.PlaybackFullscreenActivity@322837504 (0x133e1c00)
D/LeakCanary: | mLock = java.lang.Object@319489728 (0x130b06c0)
D/LeakCanary: | mPackageName = null
D/LeakCanary: | mSessionBinder = android.media.session.ISessionController$Stub$Proxy@319491728 (0x130b0e90)
D/LeakCanary: | mTag = null
D/LeakCanary: | mToken = android.media.session.MediaSession$Token@319489760 (0x130b06e0)
D/LeakCanary: | mTransportControls = android.media.session.MediaController$TransportControls@319489744 (0x130b06d0)
D/LeakCanary: | shadow$_klass_ = android.media.session.MediaController
D/LeakCanary: | shadow$_monitor_ = 0
D/LeakCanary: * Instance of com.me.ui.playback.PlaybackFullscreenActivity
D/LeakCanary: | static $staticOverhead = byte[16]@317706241 (0x12efd001)
D/LeakCanary: | static serialVersionUID = 0
D/LeakCanary: | static $change = null
D/LeakCanary: | mToolbar = android.support.v7.widget.Toolbar@321094656 (0x13238400)
D/LeakCanary: | playbackFragment = com.me.ui.playback.PlaybackFragment@318524080 (0x12fc4ab0)
D/LeakCanary: | mDelegate = android.support.v7.app.AppCompatDelegateImplV23@320052000 (0x13139b20)
D/LeakCanary: | mEatKeyUpEvent = false
D/LeakCanary: | mResources = null
D/LeakCanary: | mThemeId = 2131427393
D/LeakCanary: | mCreated = true
D/LeakCanary: | mFragments = android.support.v4.app.FragmentController@323740768 (0x134be460)
D/LeakCanary: | mHandler = android.support.v4.app.FragmentActivity$1@323839264 (0x134d6520)
D/LeakCanary: | mNextCandidateRequestIndex = 0
D/LeakCanary: | mOptionsMenuInvalidated = false
D/LeakCanary: | mPendingFragmentActivityResults = android.support.v4.util.SparseArrayCompat@323840160 (0x134d68a0)
D/LeakCanary: | mReallyStopped = true
D/LeakCanary: | mRequestedPermissionsFromFragment = false
D/LeakCanary: | mResumed = false
D/LeakCanary: | mRetaining = false
D/LeakCanary: | mStopped = true
D/LeakCanary: | mStartedActivityFromFragment = false
D/LeakCanary: | mStartedIntentSenderFromFragment = false
D/LeakCanary: | mExtraDataMap = android.support.v4.util.SimpleArrayMap@323839232 (0x134d6500)
D/LeakCanary: | mActionBar = null
D/LeakCanary: | mActionModeTypeStarting = 0
D/LeakCanary: | mActivityInfo = android.content.pm.ActivityInfo@319807616 (0x130fe080)
D/LeakCanary: | mActivityTransitionState = android.app.ActivityTransitionState@323795264 (0x134cb940)
D/LeakCanary: | mApplication = com.me.MainApplication@314898704 (0x12c4f910)
D/LeakCanary: | mCalled = true
D/LeakCanary: | mChangeCanvasToTranslucent = false
D/LeakCanary: | mChangingConfigurations = false
D/LeakCanary: | mComponent = android.content.ComponentName@323825776 (0x134d3070)
D/LeakCanary: | mConfigChangeFlags = 0
D/LeakCanary: | mCurrentConfig = android.content.res.Configuration@323855456 (0x134da460)
D/LeakCanary: | mDecor = null
D/LeakCanary: | mDefaultKeyMode = 0
D/LeakCanary: | mDefaultKeySsb = null
D/LeakCanary: | mDestroyed = true
D/LeakCanary: | mDoReportFullyDrawn = false
D/LeakCanary: | mEmbeddedID = null
D/LeakCanary: | mEnableDefaultActionBarUp = false
D/LeakCanary: | mEnterTransitionListener = android.app.SharedElementCallback$1@1888376616 (0x708e5728)
D/LeakCanary: | mExitTransitionListener = android.app.SharedElementCallback$1@1888376616 (0x708e5728)
D/LeakCanary: | mFinished = true
D/LeakCanary: | mFragments = android.app.FragmentController@323740720 (0x134be430)
D/LeakCanary: | mHandler = android.os.Handler@323839136 (0x134d64a0)
D/LeakCanary: | mIdent = 169286722
D/LeakCanary: | mInstanceTracker = android.os.StrictMode$InstanceTracker@323740736 (0x134be440)
D/LeakCanary: | mInstrumentation = android.app.Instrumentation@315044816 (0x12c733d0)
D/LeakCanary: | mIntent = android.content.Intent@323821632 (0x134d2040)
D/LeakCanary: | mLastNonConfigurationInstances = null
D/LeakCanary: | mMainThread = android.app.ActivityThread@314791872 (0x12c357c0)
D/LeakCanary: | mManagedCursors = java.util.ArrayList@323839168 (0x134d64c0)
D/LeakCanary: | mManagedDialogs = null
D/LeakCanary: | mMenuInflater = null
D/LeakCanary: | mParent = null
D/LeakCanary: | mReferrer = java.lang.String@323822208 (0x134d2280)
D/LeakCanary: | mResultCode = 0
D/LeakCanary: | mResultData = null
D/LeakCanary: | mResumed = false
D/LeakCanary: | mSearchEvent = null
D/LeakCanary: | mSearchManager = null
D/LeakCanary: | mStartedActivity = false
D/LeakCanary: | mStopped = true
D/LeakCanary: | mTemporaryPause = false
D/LeakCanary: | mTitle = java.lang.String@314691776 (0x12c1d0c0)
D/LeakCanary: | mTitleColor = 0
D/LeakCanary: | mTitleReady = true
D/LeakCanary: | mToken = android.os.BinderProxy@323829824 (0x134d4040)
D/LeakCanary: | mTranslucentCallback = null
D/LeakCanary: | mUiThread = java.lang.Thread@1955762776 (0x74929258)
D/LeakCanary: | mVisibleBehind = false
D/LeakCanary: | mVisibleFromClient = true
D/LeakCanary: | mVisibleFromServer = true
D/LeakCanary: | mVoiceInteractor = null
D/LeakCanary: | mWindow = com.android.internal.policy.PhoneWindow@317655136 (0x12ef0860)
D/LeakCanary: | mWindowAdded = true
D/LeakCanary: | mWindowManager = android.view.WindowManagerImpl@323839680 (0x134d66c0)
D/LeakCanary: | mInflater = com.android.internal.policy.PhoneLayoutInflater@323776416 (0x134c6fa0)
D/LeakCanary: | mOverrideConfiguration = null
D/LeakCanary: | mResources = android.content.res.Resources@315044736 (0x12c73380)
D/LeakCanary: | mTheme = android.content.res.Resources$Theme@323839712 (0x134d66e0)
D/LeakCanary: | mThemeResource = 2131427393
D/LeakCanary: | mBase = android.app.ContextImpl@319796480 (0x130fb500)
D/LeakCanary: | shadow$_klass_ = com.me.ui.playback.PlaybackFullscreenActivity
D/LeakCanary: | shadow$_monitor_ = 1293121552
D/LeakCanary: * Excluded Refs:
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mNextServedView
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mServedView
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mCurRootView
D/LeakCanary: | Field: android.os.UserManager.mContext
D/LeakCanary: | Field: android.net.ConnectivityManager.sInstance
D/LeakCanary: | Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
D/LeakCanary: | Thread:FinalizerWatchdogDaemon (always)
D/LeakCanary: | Thread:main (always)
D/LeakCanary: | Thread:LeakCanary-Heap-Dump (always)
D/LeakCanary: | Class:java.lang.ref.WeakReference (always)
D/LeakCanary: | Class:java.lang.ref.SoftReference (always)
D/LeakCanary: | Class:java.lang.ref.PhantomReference (always)
D/LeakCanary: | Class:java.lang.ref.Finalizer (always)
D/LeakCanary: | Class:java.lang.ref.FinalizerReference (always)
Can anybody help me?
Thanks in advance.
This leak was fixed and released in 25.2.0 support library. Font: issuetracker
MediaControllerCompat.setMediaController()
instantiates controllerObj
. Then this object is used to perform setMediaController(activity, controllerObj)
. After this is performed, I see no seams that would make controllerObj
not to be leaked. In other words, it seems that one should take care of nulling out that object on his own:
MediaSessionCompat mediaSessionCompat = ...;
MediaController mediaController =
(MediaController) mediaSessionCompat.getController().getMediaController();
// explicitly nulling out MediaController
mediaController = null;
Note, that performing MediaControllerCompat.setMediaController(this, null)
would not make previously set object to be nulled out, rather it would just update current instance with the new one. But controllerObj
keeps a hard reference to the hosting activity and no one had taken care of nulling it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With