I am relatively new to the scene with little programming background, therefore I apologise in advance if I ask something silly. I am show a google map using SupportMapFragment. I am doing this to prevent a leak in onDestroyView(), however no clue whether this is right or wrong?
@Override protected void onDestroy() { super.onDestroy(); mMap.clear(); mapView.onDestroy(); }
Full code is here:
https://github.com/warfo09/warforepo/blob/main/MainActivity.java
This is what I get when I exit my application:
│ GC Root: Local variable in native code │ ├─ com.google.maps.api.android.lib6.gmm6.vector.n instance │ Leaking: UNKNOWN │ Retaining 1391172 bytes in 9076 objects │ Thread name: 'RenderDrive' │ ↓ n.e │ ~ ├─ com.google.maps.api.android.lib6.gmm6.vector.p instance │ Leaking: UNKNOWN │ Retaining 1391005 bytes in 9073 objects │ ↓ p.k │ ~ ├─ com.google.maps.api.android.lib6.gmm6.api.ac instance │ Leaking: UNKNOWN │ Retaining 1390953 bytes in 9072 objects │ View not part of a window view hierarchy │ View.mAttachInfo is null (view detached) │ View.mWindowAttachCount = 1 │ mContext instance of android.app.Application │ ↓ ac.mParent │ ~~~~~~~ ├─ android.widget.FrameLayout instance │ Leaking: UNKNOWN │ Retaining 405651 bytes in 5497 objects │ View not part of a window view hierarchy │ View.mAttachInfo is null (view detached) │ View.mWindowAttachCount = 1 │ mContext instance of android.app.Application │ ↓ FrameLayout.mParent │ ~~~~~~~ ├─ com.google.android.gms.maps.MapView instance │ Leaking: YES (View.mContext references a destroyed activity) │ Retaining 403455 bytes in 5482 objects │ View not part of a window view hierarchy │ View.mAttachInfo is null (view detached) │ View.mID = R.id.mapsView │ View.mWindowAttachCount = 1 │ mContext instance of com.app.trikojis.MainActivity with mDestroyed = true │ ↓ MapView.mContext ╰→ com.app.trikojis.MainActivity instance Leaking: YES (ObjectWatcher was watching this because com.app.trikojis.MainActivity received Activity#onDestroy() callback and Activity#mDestroyed is true) Retaining 60455 bytes in 956 objects key = f3613896-cce8-4aac-a73a-d4a79700c719 watchDurationMillis = 56451 retainedDurationMillis = 51448 mApplication instance of android.app.Application mBase instance of androidx.appcompat.view.ContextThemeWrapper, not wrapping known Android context METADATA Build.VERSION.SDK_INT: 28 Build.MANUFACTURER: samsung LeakCanary version: 2.5 App process name: com.app.trikojis Stats: LruCache[maxSize=3000,hits=5749,misses=110455,hitRate=4%] RandomAccess[bytes=5714581,reads=110455,travel=48839777691,range=35924253,size=41590935] Analysis duration: 11845 ms```
Advertisement
Answer
The leaktrace indicates that MainActivity was destroyed but is held in memory by MapView which has the activity as its context.
Now, what’s really weird here is that the MapView is the parent of a FrameLayout that has the Application as its context, which itself is the parent of a view called ‘ac’ (obfuscated name) which is held by a field of the “RenderDrive” thread instance.
This definitely is a bug in the Google Maps library. You should report the issue on their bug tracker, feel free to also use this answer that I just posted.
I don’t know what bug exactly is causing this leak, but you could fix it by removing all children of MapView when the activity is destroyed.
@Override protected void onDestroy() { super.onDestroy(); mMap.clear(); mapView.onDestroy(); mapView.removeAllViews(); }