Maximilian Speicher
Maximilian Speicher

Reputation: 575

Google Maps MapsView leaking

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

Answers (1)

faizy
faizy

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

Related Questions