18

Thank you for taking the time to read this.

I published an app to the Google Play store about a month ago(08/29/14) and this wasn't a problem with the same amount of markers. This week, i've noticed when i went onto my app that loading the 400 markers to the map took about 10-20 seconds on my Galaxy S5 and that there is a small circle in the middle of the default map marker icons. Before this, the map loaded in less than a second. I haven't updated or changed my app. I'm guessing Google updated the Google Map API and the change made it much slower to load markers? Has this happened to anyone else? Does anyone else have information about this?

My app is available for free on the Play Store. You can search NYS Canal Guide to find it if you want to see how slow it loads.

This method gets called in the onCreateView() of the map fragment after the map is initialized:

    private void addExistingMarkersToMap(){
    log("Adding existing markers to the map. poiAdapter size = " + poiAdapter.getCount());
    Marker marker;
    MarkerOptions markerOptions;

    for(MapMarker mapMarker : poiAdapter){
        if(markersNotFilteredOut(mapMarker)){
            markerOptions = mapMarker.getMarkerOptions();

            if(markerOptions != null && mapMarker != null){
                marker = mMap.addMarker(markerOptions);
                mapMarker.setMarker(marker);
            }
        }
    }
}

This is the getMarkerOptions() method on a MapMarker class:

public MarkerOptions getMarkerOptions() {
    return new MarkerOptions()
    .title(name)
    .position(new LatLng(lat, lng))
    .snippet(bodyOfWater + ", mile " + mile)
    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
}

The full source code is here: github.com/olearyj234/NYS-Canal-Guide

EDIT:

** To be specific, the only part that is slow is loading the markers when the map is being initialized(so also when switching from one navigation tab and back to the map tab). It isn't slow when moving the map or anything else.

Here are some logs that come up:

While the screen is frozen for a few seconds(5-15) because its loading the markers, this log is being produced very fast. The bitmap id continues to increment by one and while the markers are loading, it produces about 400 of these logs. This shows that it has to be a problem related to loading the marker bitmaps on the screen. I'm using the default marker bitmap.

   10-01 15:45:07.222: D/skia(32108): GFXPNG PNG bitmap created width:16 height:32 bitmap id is 414

This log is produced when the app is finished loading all the markers to the map.

10-01 15:51:09.402: I/Choreographer(8353): Skipped 1130 frames!  The application may be doing too much work on its main thread.

This log is produced 14 times when the app is finished loading all the markers to the map.

10-01 15:59:13.882: I/dalvikvm-heap(8353): Grow heap (frag case) to 40.668MB for 4194320-byte allocation

EDIT 2:

I just checked to see how long it would take for certain lines of code. I used System.currentTimeMillis(); in order to get times. In the method addExistingMarkersToMap(), this is the line that took long: marker = mMap.addMarker(markerOptions); When adding all 400 markers, it took 54 ms on average for each marker. The min time was 34ms and the max was 114ms.

If there's any more information you think i should provide, let me know in a comment. Thank you!

James
  • 4,573
  • 29
  • 32
  • I have reproduced this error too and even if you cache the icon `BitmapDescriptor` adding the marker is slow. – eliocs Sep 30 '14 at 12:34
  • @eliocs Has this just happened to you in the past month also? I'm actively searching for a solution but i can't figure this problem out. Also, how do you choose to cache the BitmapDescriptor icon? – James Oct 01 '14 at 19:25
  • They may have redone the API a bit due to the wearable API coming out, assuming the wearables will be pretty GPS (thus possibly map) heavy. Complete guess though, but if you haven't changed anything that is my 2 cents. – zgc7009 Oct 01 '14 at 20:19
  • @zgc7009 I agree, i think they changed their API's since i haven't changed anything. Whatever they changed, i think it has something to do with adding the bitmaps to the map. Can you look at the logs i just added to the original posts? Thank you! – James Oct 02 '14 at 02:27
  • 1
    There is an intermediate solution, add only the markers that are visible on the map. As suggested here: http://stackoverflow.com/questions/13713066/google-maps-android-api-v2-very-slow-when-adding-lots-of-markers – eliocs Oct 02 '14 at 08:25
  • @olearyj234 I am seeing exactly the same behaviour with ~390 markers. No changes were published, it just started happening. I only noticed it today. Have you found any solution/workaround? – myanimal Oct 04 '14 at 13:39

2 Answers2

13

This appears to be a new problem introduced in Google Maps API v2 (looks like one of the Play Services 6 updates), see #7174 for more info (and please star it).

From the info provided in the issue, the problem seems to be specific to using a default marker with a hue, e.g.:

BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)

There are some workarounds. Easiest is to not provide a hue (if all your markers being red is acceptable):

BitmapDescriptorFactory.defaultMarker()

Or use custom drawables:

BitmapDescriptorFactory.fromResource(R.drawable.map_marker)

I see a ~2000 times slowdown when using the default marker with a hue. I'm going with the custom drawables as a solution for now.

myanimal
  • 3,580
  • 26
  • 26
  • 1
    7174 is my bug. I have found another change Google made - you used to only be able to use the statically defined colors they have in the factory (HUE_RED). If you supplied a undefined float it would simply use the nearest defined color. Now you can use any float to get dynamic shades. I would bet this is where they introduced the problem. – Nemi Oct 05 '14 at 12:39
  • @myanimal Thank you for the great response. I starred the 7174 bug. Does anyone know a good set of icons i could use for my markers that are free? I want to find a set and use the fromResource method. If i find a good set, i'll post a link here. – James Oct 05 '14 at 18:44
  • I starred it as well. The problem occurs with me with around 500 default markers and custom hue. After removing the custom hue it worked like a charm. Therefore confirming the hue as the problem! – PLM57 Oct 17 '14 at 10:04
  • It also worked after I changed from using custom hues of the default marker to my custom markers (i created them in photoshop) using the fromResource method. Hopefully they will fix this bug soon for others using the default marker with different hues. – James Oct 18 '14 at 23:00
  • 5
    If anyone that's having these issues wants to use the icons that i have created using photoshop, feel free. You can find them under https://github.com/olearyj234/NYS-Canal-Guide/tree/master/res in the "drawable" folders. Each icon filename starts with "mmi". You can then use `BitmapDescriptorFactory.fromResource(R.drawable.map_marker)` to avoid this bug – James Nov 04 '14 at 17:57
  • 1
    This bug has been fixed in Google play services according to that link. I can confirm that it is working for me now. – Nemi Feb 18 '15 at 14:59
4

It is my understanding that each time you draw a marker it sends the drawing operations to a thread pool in the background while it returns the marker. It is easy to overwhelm the CPU by flooding the request through too quickly.
Use the handler from the main looper and and post delayed at increasing intervals to spread out the operations as in the code below.

Handler handler = new Handler(Looper.getMainLooper());
int x = 0;
long DELAY = 10;
for(MapMarker mapMarker : poiAdapter){
    if(markersNotFilteredOut(mapMarker)){
        markerOptions = mapMarker.getMarkerOptions();

        if(markerOptions != null && mapMarker != null){
           handler.postDelayed(
                   new Runnable() {
                      @Override
                      public void run() {
                          marker = mMap.addMarker(markerOptions);
                          mapMarker.setMarker(marker);
                      }
                   }, (DELAY * (long)x++));
        }
    }
}
John Fontaine
  • 1,019
  • 9
  • 14
  • I changed the code so it was like what you have above but it still gave me the same delay. I edited the original post to include some logs. Maybe that can help you help me? Thank you for your reply! – James Oct 02 '14 at 02:23