Reputation: 575
I´ve added a Google Maps MapView to a Fragment in Android. Until now it is a clear Map without any Markers, Options or anything else. Nevertheless whenever I leave the Fragment the app has a memory leak.
I´ve already tried all proposed solutions that I have found like attaching the MapView to the Fragment Lifecycle, setting it no null in onDestroyView()
and so on but the memory leak still prevails.
The current code looks like this:
fragment_map.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
MapViewFragment.java
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_map, container, false);
mMapView = view.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
MapsInitializer.initialize(Objects.requireNonNull(getActivity()).getApplicationContext());
mMapView.getMapAsync(googleMap -> {
mGoogleMap = googleMap;
});
return view;
}
@Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
@Override
public void onDestroyView() {
mGoogleMap.clear();
mMapView.onDestroy();
mGoogleMap = null;
mMapView = null;
super.onDestroyView();
}
The leak trace looks like this:
┬
├─ com.google.android.gms.internal.location.zzat
│ Leaking: NO (it's a GC root)
│ ↓ zzat.zzda
│ ~~~~
├─ com.google.android.gms.common.api.internal.ListenerHolder
│ Leaking: UNKNOWN
│ ↓ ListenerHolder.zajl
│ ~~~~
├─ com.google.android.gms.common.api.internal.ListenerHolder$ListenerKey
│ Leaking: UNKNOWN
│ ↓ ListenerHolder$ListenerKey.zajk
│ ~~~~
├─ package.fragments.MapViewFragment$1
│ Leaking: UNKNOWN
│ Anonymous subclass of com.google.android.gms.location.LocationCallback
│ ↓ MapViewFragment$1.this$0
│ ~~~~~~
╰→ package.fragments.MapViewFragment
Leaking: YES (RefWatcher was watching this and Fragment#mFragmentManager is null and Fragment#mFragmentManager is null)
, retainedHeapSize=null), LeakingInstance(referenceKey=3a478407-69a0-4916-8035-42c2bfd2af4e, referenceName=, instanceClassName=android.widget.RelativeLayout, watchDurationMillis=123593, retainedDurationMillis=118589, exclusionStatus=null, leakTrace=
┬
├─ com.google.maps.api.android.lib6.gmm6.vector.q
│ Leaking: NO (it's a GC root)
│ Thread name: 'RenderDrive'
│ ↓ thread q.f
│ ~
├─ com.google.maps.api.android.lib6.gmm6.vector.n
│ Leaking: UNKNOWN
│ ↓ n.k
│ ~
├─ com.google.maps.api.android.lib6.gmm6.api.y
│ Leaking: YES (View detached and has parent)
│ View#mParent is set
│ View#mAttachInfo is null (view detached)
│ View.mWindowAttachCount=1
│ ↓ y.mParent
├─ android.widget.FrameLayout
│ Leaking: YES (y↑ is leaking and View detached and has parent)
│ View#mParent is set
│ View#mAttachInfo is null (view detached)
│ View.mWindowAttachCount=1
│ ↓ FrameLayout.mParent
├─ com.google.android.gms.maps.MapView
│ Leaking: YES (FrameLayout↑ is leaking and View detached and has parent)
│ View#mParent is set
│ View#mAttachInfo is null (view detached)
│ View.mWindowAttachCount=1
│ ↓ MapView.mParent
╰→ android.widget.RelativeLayout
Leaking: YES (RefWatcher was watching this)
View#mParent is null
View#mAttachInfo is null (view detached)
View.mWindowAttachCount=1, retainedHeapSize=null)])
However I´ve already tried moving the lifecycle methods around from onDestroy
to onDestroyView
and so on.
The memory leak is about 1 to 2 MB every time I leave the MapFragment. I hope this leak can be fixed, but I don´t have any idea what to try anymore.
Upvotes: 6
Views: 1890
Reputation: 749
To avoid memory leaks in map view,should add following things on fragment's onDestroyView
.
@Override
public void onDestroyView() {
googleMap.clear()
mMapView.removeAllViews()
mMapView?.onDestroy()
super.onDestroyView()
}
Upvotes: 0