Android MapView v2 Context Issues and Memory Leak
Asked Answered
S

4

2

I'm using MapView v2 in my application (not MapFragment) and it's causing a memory leak. The leak occurs when I pass the Activity context to the MapView constructor. If I pass the Application Context to the MapView constructor the memory leak goes away, however the MapView starts performing badly when I scroll the ScrollView it's in.

Here's a snapshot of where the leak is happening:

enter image description here

The relevant code in MapView is:

public class MapView extends android.widget.FrameLayout {
  private final com.google.android.gms.maps.MapView.b gD;

  static class b extends com.google.android.gms.dynamic.a<com.google.android.gms.maps.MapView.a> {
    private final android.content.Context mContext;
    // Here's the Context MapView is leaking

  }

  static class a implements com.google.android.gms.dynamic.LifecycleDelegate {
    // More stuff in here
  }
}

I've been messing with MapView for a few weeks now trying to get it to behave correctly in a ScrollView, to no avail. I'm about to give up on it.

Also, the snapshot() method that was recently added isn't an option because I have already tried it, and it doesn't give a reliable snapshot of the map. I have an open question on this here, and another related open question here and here, all of which have not been answered.

Sapanwood answered 27/9, 2013 at 23:16 Comment(0)
C
3

In project that I was working we had similar issue. We were using mapView inside viewholder. Solution was to call onPause and then onDestroy on mapview. After that memory leaks were not observed.

Cheyenne answered 24/7, 2015 at 9:14 Comment(0)
O
3

Possibily related to danielgomezrico's answer, there is a confirmed bug related to my location layer in MapView that leaks memory.

The workaround is to make sure you disable my location using GoogleMap.setMyLocationEnabled(false) before the map is destroyed. Also make sure to call other map view's lifecycle methods as well.

private MapView mMapView;
private GoogleMap mMap;

...

@Override
public void onResume() {
    super.onResume();
    mMapView.onResume();
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mMapView.onSaveInstanceState(outState);
}

@Override
public void onPause() {
    super.onPause();
    mMapView.onPause();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    mMapView.onLowMemory();
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mMap != null) {
        mMap.setMyLocationEnabled(false);
    }
    mMapView.onDestroy();
}
Oneil answered 1/10, 2015 at 3:41 Comment(1)
this was the solution for meSubclavius
C
2

I've been messing with MapView for a few weeks now trying to get it to behave correctly in a ScrollView, to no avail. I'm about to give up on it.

Honestly, that's for the best. MapView is likely never going to play nice inside of a ScrollView. There are a host of bugs that crop up when this combination is used; vertical lag, the MapView rendering over the ActionBar, vertical scrolling simply not working, etc. Removing the ScrollView is not only preferred but most likely required.

That said, if you absolutely must do this, because of client constraints for example, you have two options.

  1. You can use Snapshot & the SnapshotReady callback; when the callback is fired, replace the MapView with an ImageView of the snapshot. You lose interactivity but you also lose the problems you're experiencing. (You're claiming this doesn't work or draws an incomplete bitmap, though I haven't run into that issue. I'm not sure how you're implementing it.)

  2. Write a custom class extending the MapView, override onTouchEvent and for whatever motion events you need to fix (probably ACTION_DOWN and ACTION_UP), manually control whether or not the parent (the ScrollView) can intercept the action. Use something like this.getParent().requestDisallowInterceptTouchEvent(true|false) depending on your case. Check the Android docs for more info on that method.

I hope that helps!

Chewink answered 27/9, 2013 at 23:50 Comment(4)
1. It draws an incomplete bitmap because I don't create the MapView right away, I have to wait for a Loader to complete with some data to build a custom View that has my MapView in it. I tried calling snapshot with the listener after I build the MapView with the options etc. but when the listener is fired the MapView hasn't finished rendering the map yet, so you'll randomly see 0% to 100% of the map rendered in the Bitmap that gets passed back by the callback.Sapanwood
Not sure how you're doing it, but you shouldn't be calling for a snapshot until after your MapView has finished rendering. Feel free to make a new post and I can try to help you through it.Chewink
That's the crux of the issue, there's no callback to tell you when the map has finished rendering. It seems that the snapshot method is meant to be triggered from a button press or something.Sapanwood
It is always good to have the possibility to tell your customer "No you cannot have it sorry. It is technically impossible / not advisable". I certainly do.Keefe
D
2

Are you using it inside a fragment? Maybe related to this bug https://code.google.com/p/android/issues/detail?id=185902

Dry answered 10/9, 2015 at 6:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.