2

I'd like to display many icons with the Google API (more than 2,000 icons). I created a simple activity, based on this tuto .

It displays without any problem icons when accessing the map. However, when I zoom in/out a few times, a java.lang.OutOfMemoryError:

12-16 08:48:29.415: E/dalvikvm-heap(606): 680640-byte external allocation too large for this process.
12-16 08:48:29.415: E/GraphicsJNI(606): VM won't let us allocate 680640 bytes
12-16 08:48:29.415: D/AndroidRuntime(606): Shutting down VM
12-16 08:48:29.415: W/dalvikvm(606): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
12-16 08:48:29.425: E/AndroidRuntime(606): FATAL EXCEPTION: main
12-16 08:48:29.425: E/AndroidRuntime(606): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.graphics.Bitmap.nativeCreate(Native Method)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.google.android.maps.ZoomHelper.createSnapshot(ZoomHelper.java:444)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.google.android.maps.ZoomHelper.doZoom(ZoomHelper.java:151)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.google.android.maps.ZoomHelper.doZoom(ZoomHelper.java:140)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.google.android.maps.MapView.doZoom(MapView.java:1478)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.google.android.maps.MapView.doZoom(MapView.java:1487)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.google.android.maps.MapView$4.onClick(MapView.java:1381)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.view.View.performClick(View.java:2408)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.view.View$PerformClick.run(View.java:8816)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.os.Handler.handleCallback(Handler.java:587)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.os.Handler.dispatchMessage(Handler.java:92)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.os.Looper.loop(Looper.java:123)
12-16 08:48:29.425: E/AndroidRuntime(606):  at android.app.ActivityThread.main(ActivityThread.java:4627)
12-16 08:48:29.425: E/AndroidRuntime(606):  at java.lang.reflect.Method.invokeNative(Native Method)
12-16 08:48:29.425: E/AndroidRuntime(606):  at java.lang.reflect.Method.invoke(Method.java:521)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
12-16 08:48:29.425: E/AndroidRuntime(606):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
12-16 08:48:29.425: E/AndroidRuntime(606):  at dalvik.system.NativeStart.main(Native Method)

Here is my activity method:

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);    
    requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);     
    setContentView(R.layout.google_map);       

    Bundle bundle = getIntent().getExtras();

    //MAP    
    mapView = (MapView) findViewById(R.id.mapView);

    //zoom設定
    LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
    View zoomView = mapView.getZoomControls(); 

    zoomLayout.addView(zoomView, 
       new LinearLayout.LayoutParams(
           LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT)); 
    mapView.displayZoomControls(true);

    //controller
    mc = mapView.getController();

    double[] adresse = (double[]) bundle.getDoubleArray(Site.LATTITUDE);     
    p = new GeoPoint((int) (adresse[0] * 1E6), (int) (adresse[1] * 1E6));

    mc.animateTo(p);
    mc.setZoom(18); 
    mapView.invalidate();

    List<Overlay> listOfOverlays = mapView.getOverlays();
    listOfOverlays.clear();

    try {

        //get datas from previous activiity
        List<SiteGoogle> sitesList = bundle.getParcelableArrayList(Site.JSON_ARRAY);

        //display message
        Toast.makeText(getBaseContext(), getResources().getString(R.string.map_toad), Toast.LENGTH_LONG).show();

        List<Overlay> mapOverlays = mapView.getOverlays();
        mapOverlays.clear();

        for(SiteGoogle site: sitesList) {  

            //set icon
            Drawable drawable = this.getResources().getDrawable(R.drawable.icon01);

            //icon setting
            MapItemizedOverlay itemizedoverlay = new MapItemizedOverlay(drawable,this);    

            //geoPoint
            GeoPoint point = new GeoPoint((int) (site.getLatitude() * 1E6), (int) (site.getLongitude() * 1E6));

            //item
            OverlayItem overlayitem = new OverlayItem(point, String.valueOf(site.getId()), null);

            itemizedoverlay.addOverlay(overlayitem);

            //add to map
            mapOverlays.add(itemizedoverlay);

        }

    } catch(Exception e) {
        Log.e(TAG,e.getMessage());
    }

And my MapItemizedOverlay class:

@SuppressWarnings("rawtypes")
public class MapItemizedOverlay extends ItemizedOverlay {

    private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
    private Context mContext;

    public MapItemizedOverlay(Drawable defaultMarker, Context context) {
        super(boundCenterBottom(defaultMarker));
        mContext = context;
    }

    public void addOverlay(OverlayItem overlay) {
        mOverlays.add(overlay);
        populate();
    }

    @Override
    protected OverlayItem createItem(int i) {
        return mOverlays.get(i);
    }

    @Override
    public int size() {
        return mOverlays.size();
    }

    @Override
    protected boolean onTap(int index){

        OverlayItem item = mOverlays.get(index);

        Intent intent = new Intent(mContext, SiteDetailsActivity.class);
        intent.putExtra(Site.ID, Integer.parseInt(item.getTitle()));        
        mContext.startActivity(intent);

        return true;
    }

I don't know what I can do to make it faster and not crashing. Should I use canvas, or cache? I have no ideas.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
johann
  • 1,115
  • 8
  • 34
  • 60

2 Answers2

0

I'm not sure that it will help, but you are adding an Overlay per site in your loop over sitesList to the map:

for(SiteGoogle site: sitesList){  

        //set icon
        Drawable drawable = this.getResources().getDrawable(R.drawable.icon01);


       //icon setting
       MapItemizedOverlay itemizedoverlay = new MapItemizedOverlay(drawable,this);    

       //geoPoint
       GeoPoint point = new GeoPoint((int) (site.getLatitude() * 1E6), (int) (site.getLongitude() * 1E6));

       //item
       OverlayItem overlayitem = new OverlayItem(point, String.valueOf(site.getId()), null);

       itemizedoverlay.addOverlay(overlayitem);

       //add to map
       mapOverlays.add(itemizedoverlay);

        }

So you end up having 2000 Overlays and 2000 Drawables and this is not good.

An ItemizedOverlay can be used in much more effective way:

Drawable drawable = this.getResources().getDrawable(R.drawable.icon01);
MapItemizedOverlay itemizedoverlay = new MapItemizedOverlay(drawable,this);

for(SiteGoogle site: sitesList) {  
    GeoPoint point = new GeoPoint((int) (site.getLatitude() * 1E6), (int) (site.getLongitude() * 1E6));
    OverlayItem overlayitem = new OverlayItem(point, String.valueOf(site.getId()), null);

    itemizedoverlay.addOverlay(overlayitem);
}
mapOverlays.add(itemizedoverlay);
Darth Beleg
  • 2,657
  • 24
  • 26
0

As Darth Beleg said, I put "mapOverlays.add(itemizedoverlay)" out of the loop, and I have changee position of "mapView.invalidate()". But nothing appears.

Dead line for this project is in few days, and I have to solve this issue today. I would be happy if someone could help me.

New code for activity:

  public void onCreate(Bundle savedInstanceState) {

           super.onCreate(savedInstanceState);     
           requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);      
           setContentView(R.layout.google_map);    

           //SearchActivity parameters
           Bundle bundle = getIntent().getExtras();

           //MAP     
           mapView = (MapView) findViewById(R.id.mapView);

           //zoom設定
           LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
           View zoomView = mapView.getZoomControls(); 

           zoomLayout.addView(zoomView, 
               new LinearLayout.LayoutParams(
                   LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT)); 
           mapView.displayZoomControls(true);

          mc = mapView.getController();

          double[] adresse = (double[]) bundle.getDoubleArray(Site.LATTITUDE);     
           p = new GeoPoint((int) (adresse[0] * 1E6), (int) (adresse[1] * 1E6));

           mc.animateTo(p);
           mc.setZoom(18); 


           //get current position
           List<Overlay> listOfOverlays = mapView.getOverlays();
           listOfOverlays.clear();

           try{

               //get icon position informations
               List<SiteGoogle> sitesList = bundle.getParcelableArrayList(Site.JSON_ARRAY);

                //message diplay
               Toast.makeText(getBaseContext(), getResources().getString(R.string.map_toad), Toast.LENGTH_LONG).show();

               List<Overlay> mapOverlays = mapView.getOverlays();
               mapOverlays.clear();

               MapItemizedOverlay itemizedoverlay = null;

               for(SiteGoogle site: sitesList){   

                   //set the icon
                   Drawable drawable;

                   switch (site.getCategory()){
                       case 1:
                           drawable = this.getResources().getDrawable(R.drawable.icon01);
                           break;
                       case 2:
                           drawable = this.getResources().getDrawable(R.drawable.icon02);
                           break;
                       case 3:
                           drawable = this.getResources().getDrawable(R.drawable.icon03);
                           break;
                       case 4:
                           drawable = this.getResources().getDrawable(R.drawable.icon04);
                           break;
                       case 5:
                           drawable = this.getResources().getDrawable(R.drawable.icon05);
                           break;
                       case 6:
                           drawable = this.getResources().getDrawable(R.drawable.icon06);
                           break;
                       case 7:
                           drawable = this.getResources().getDrawable(R.drawable.icon07);
                           break;
                       case 0:
                           drawable = this.getResources().getDrawable(R.drawable.icon00);
                           break;
                       default:
                           drawable = this.getResources().getDrawable(R.drawable.icon01);
                           break;
                   }


                itemizedoverlay = new MapItemizedOverlay(drawable,this);

               //geoPoint
               GeoPoint point = new GeoPoint((int) (site.getLatitude() * 1E6), (int) (site.getLongitude() * 1E6));

               //item
               OverlayItem overlayitem = new OverlayItem(point, String.valueOf(site.getId()), null);

               itemizedoverlay.addOverlay(overlayitem);

                }

               //add to map
               mapOverlays.add(itemizedoverlay);

               mapView.invalidate();

           }catch(Exception e){
              Log.e(TAG,e.getMessage());
          }

}
johann
  • 1,115
  • 8
  • 34
  • 60
  • Did you fix it? Having a similar problem here, using Phonegap and Google Maps – Sebastian Mar 11 '13 at 17:29
  • 1
    I' ve put all the similar icons in a single MapItemizedOverlay and it worked perfectly. Did you fix it ? – johann Mar 12 '13 at 01:02
  • Ah ok, but this works only if you are using the native version of Google Maps Api, isn't it? There is no possibility to use this in the Javascript Google Maps API, isn't it? – Sebastian Mar 13 '13 at 09:40