Efficient Map Overlays in Android Google Map

后端 未结 5 1307
北恋
北恋 2020-12-04 07:50

I want to do the following and am kind of stuck on these for a few days:

  1. I was trying to draw polylines (I have encoded polylines, but have

相关标签:
5条回答
  • 2020-12-04 08:05

    I have the same problem. We are developing an iphone app and an android app at the same time. I have 2500 + map overlays. No problem on iphone; a huge performance hit on android when calling populate() after adding all overlays. (Of course, my first try was to call populate() every time after adding an overlay; a typical mistake due to google's tutorial. Now I am calling populate() just once, after all 2500+ overlays have been added to the ItemizedOverlay.)

    So the single populate() call takes over 40 seconds to complete on an htc hero device. I had to put in a busy indicator; no progress bar is possible because we cannot get any information about the progress of populate().

    I tried another solution: not use ItemizedOverlay but add overlays by hand, subclassing Overlay. Result: indeed it is much faster to add all those overlays to the map; however, the map becomes unusable due to constant calling of the draw() method on each overlay. In my draw method, I tried to optimize as much as possible; I do not create a bitmap every time. My draw() method looks like this:

    public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow)  {
    // our marker bitmap already includes shadow.
    // centerPoint is the geopoint where we need to put the marker.
     if (!shadow) {
      Point point = new Point();  
      mapView.getProjection().toPixels(centerPoint, point);
      canvas.drawBitmap(markerBitmap, point.x, point.y, null);
     }
    
    }
    

    Here markerBitmap is precomputed. I don't know what else I could optimize. Is there some kind of populate() call required if we are not using ItemizedOverlay??? I could not find any good answers for that.

    Right now I resort to caching the ItemizedOverlay once it has been created in a background thread. This way at least the user does not have to wait every time.

    0 讨论(0)
  • 2020-12-04 08:05

    For your 4th question.... simply use the mapOverlays.clear(); method and all the previous markers will be vanished.

    code:

    if(!mapOverlays.isEmpty()) { 
        mapOverlays.clear();
        mapView.invalidate();
    }
    
    0 讨论(0)
  • 2020-12-04 08:09

    Answers given below :

    1) Here's a solution that I used :

    /** Called when the activity is first created. */
    private List<Overlay> mapOverlays;
    
    private Projection projection;  
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        linearLayout = (LinearLayout) findViewById(R.id.zoomview);
        mapView = (MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);
    
        mapOverlays = mapView.getOverlays();        
        projection = mapView.getProjection();
        mapOverlays.add(new MyOverlay());        
    
    }
    
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
    
    class MyOverlay extends Overlay{
    
        public MyOverlay(){
    
        }   
    
        public void draw(Canvas canvas, MapView mapv, boolean shadow){
            super.draw(canvas, mapv, shadow);
    
        Paint   mPaint = new Paint();
            mPaint.setDither(true);
            mPaint.setColor(Color.RED);
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(2);
    
            GeoPoint gP1 = new GeoPoint(19240000,-99120000);
            GeoPoint gP2 = new GeoPoint(37423157, -122085008);
    
            Point p1 = new Point();
            Point p2 = new Point();
    
        Path    path = new Path();
    
        Projection  projection.toPixels(gP1, p1);
            projection.toPixels(gP2, p2);
    
            path.moveTo(p2.x, p2.y);
            path.lineTo(p1.x,p1.y);
    
            canvas.drawPath(path, mPaint);
        }
    

    courtesy: Drawing a line/path on Google Maps

    2) Here's what worked for me :

    createMarkers()
    { 
        for(elem:bigList)
        { 
            GeoPoint geoPoint = new GeoPoint((int)(elem.getLat()*1000000), (int) (elem.getLon()*1000000)); 
            OverlayItem overlayItem = new OverlayItem(geoPoint, elem.getName(), elem.getData()); 
            itemizedOverlay.addOverlay(overlayItem); 
        } 
    
        itemizedOverlay.populateNow(); 
        mapOverlays.add(itemizedOverlay); //outside of for loop 
    } 
    

    and in MyOverlay:

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

    courtesy: stackoverflow.com unknown link

    3) The best way is to use a timer class. A very detailed description of the timer class and how to use it is given at this link :

    http://life.csu.edu.au/java-tut/essential/threads/timer.html

    4) I used this code :

    if(!mapOverlays.isEmpty()) 
    { 
        mapOverlays.clear(); 
        mapView.invalidate(); 
    } 
    

    Hope these answers help atleast one other person. Thanks.

    0 讨论(0)
  • 2020-12-04 08:26

    Multiple number of drawable objects can be added to a single Overlay which can then be added to the map. Hence, drawing x number of overlay's for x number of objects wouldnt be necessary unless the objects are of different types. Code snippet.. .. Here, CustomPinPoint is my class which extends ItemizedOverlay<OverlayItem>

    CustomPinPoint customPinPoint = new CustomPinPoint(drawable, Main.this);
    
    OverlayItem tempOverLayItem = new OverlayItem(
        touchedPoint, "PinPoint", "PintPoint 2"); //Point One
    customPinPoint.insertPinPoint(tempOverLayItem);
    tempOverLayItem = new OverlayItem(new GeoPoint(
            (int)(-27.34498 * 1E6), (int)(153.00724 * 1E6)), "PinPoint",
        "PintPoint 2"); //Point Two
    customPinPoint.insertPinPoint(tempOverLayItem);
    overlayList.add(customPinPoint); //Overlay added only once
    
    0 讨论(0)
  • 2020-12-04 08:31

    For #2, I don't think you solved anything there. Your hard-to-read code is showing how to put markers on overlay and then, how to add that overlay to the map. That's exactly how I do it. I have map with around 300 hotels and it takes around 5 seconds for Android on my Nexus One to create markers. The whole thing is running inside thread and I guess I will have to do some sort of progress bar to let user know what's going on.

    I am working on app that already exists on iPhone and it seems iPhone doesn't have any issues to almost instantaneously draw these 300+ markers. I'll have hard time to explain existence of progress bar to my bosses.

    If anybody have idea how to optimize this process... I will be grateful.

    Here is my code:

        ...
            for (int m = 0; m < ArrList.size(); m++) {
                tName = ArrList.get(m).get("name").toString();
                tId = ArrList.get(m).get("id").toString();
                tLat = ArrList.get(m).get("lat").toString();;
                tLng = ArrList.get(m).get("lng").toString();;
                try {
                    lat = Double.parseDouble(tLat);
                    lng = Double.parseDouble(tLng);
                    p1 = new GeoPoint(
                            (int) (lat * 1E6), 
                            (int) (lng * 1E6));
                    OverlayItem overlayitem = new OverlayItem(p1, tName, tId);
                    itemizedoverlay.addOverlay(overlayitem);
                } catch (NumberFormatException e) {
                    Log.d(TAG, "NumberFormatException" + e);    
                }
            } 
    

    I know I could save some time by avoiding this String > Double conversion, but I don't feel that would give me significant saving.. or it would?

    0 讨论(0)
提交回复
热议问题