Search code examples
androidperformanceandroid-mapviewosmdroid

Optimize hundreds of ItemizedOverlay<Overlayitem> using OSMdroid


I'm using OSMdroid to display offline maps. I'm trying to overlayItemizedOverlay onto my mapview. And I'm able to achieve this. But the problem is I 've over a hundred(s) of items that need to be overlayed. I'm getting the data from network.

Since the number of items are too much the mapview can't handle too much data, and its slows the app down and is ANR pops most of the times. To avoid this I'm using points only related to visible screen to check it the point is in the visible screen, yes works to some extent. But the computational complexity is too much, as I'm using a single loop to compute which might take O(n2).

@Override
    public void draw(Canvas canvas,MapView mapview,boolean shadow) {
        try {

             for(int i=0;i<mItemList.size();i++) {
                    GeoPoint currGeo = mItemList.get(i).getPoint();
                    Point newPoint = new Point();
                    final Rect viewportRect = new Rect();
                    mapview.getProjection().toPixels(currGeo, newPoint);
                    viewportRect.set(mapview.getProjection().getScreenRect());
                    if(viewportRect.contains(newPoint.x, newPoint.y)){
                        super.draw(canvas, mapview, shadow);
                    }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

How can I optimize this snippet or, is there any other approaches where I can optimize, the pan scroll zoom of mapview?


Solution

  • You can "cache" the computationally expensive part of toPixels(). When you set the location on your Item you should also call:

    mProjectedPoint = mapview.getProjection().toProjectedPixels(latitude, longitude, null);
    

    and store that value in your Item for later use. When you want to get the pixel location of your Item you can call

    Point finalPoint = mapview.getProjection().toPixelsFromProjected(mProjectedPoint, null);
    

    The toPixelsFromProjected call is much faster than calling toPixels every time.

    However you also have another option - you can get the map's bounding box (which is in lat/long coordinates) and just check to see if your item's location is in the bounding box.

    Note that all of these solutions however only determine if the item's center point is in the screen. The actual drawable portion of your item (for example if it is an icon) is larger than just a single point.