Android google maps drawing roads performanse issu

2019-07-31 18:03发布

问题:

I am working on a project which is aboot drawing roads and displaying some informations about the roads. The issue is that I am using so many geopoints( 5.000-10.000 +) and drawing line points to points and showing the roads with different colors, so the map is too slow. I did some configurations about my application but still too slow. Do you have any idea about solving my problem and being the performance better?

Here is the my code.

for (int t = 0; t < roads.size(); t++) {

            for (int i = 0; i < roads.get(t).size() - 1; i++) {
                                //bounds up-bottom-right-left to draw roads
                if (boundBox[0] >= roads.get(t).get(i)
                        .getLatitudeE6()
                        && boundBox[1] >= roads.get(t).get(i)
                                .getLongitudeE6()
                        && boundBox[2] <= roads.get(t).get(i)
                                .getLatitudeE6()
                        && boundBox[3] <= roads.get(t).get(i)
                                .getLongitudeE6()) {


                    MyOverlay mOverlay = new MyOverlay();
                    mOverlay.setColor(Color.GREEN);

                    mOverlay.setWidth(4);
                    mOverlay.setPair(roads.get(t).get(i),
                            roads.get(t).get(i + 1));
                    mapOverlays.add(mOverlay);
                }
            }
        }

 class MyOverlay extends Overlay {

            GeoPoint gp1 = new GeoPoint(0, 0);
            GeoPoint gp2 = new GeoPoint(0, 0);
            int colr=0,width=0;



            public MyOverlay() {

            }

            public void draw(Canvas canvas, MapView mapv, boolean shadow) {
                super.draw(canvas, mapv, false);

                Paint mPaint = new Paint();
                mPaint.setDither(true);
                mPaint.setColor(colr);
                mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                mPaint.setStrokeJoin(Paint.Join.ROUND);
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                mPaint.setStrokeWidth(width);

                Point p1 = new Point();
                Point p2 = new Point();

                Path path = new Path();

                Projection projection = mapv.getProjection();
                projection.toPixels(gp1, p1);
                projection.toPixels(gp2, p2);

                path.moveTo((float) p2.x, (float) p2.y);
                path.lineTo((float) p1.x, (float) p1.y);


                // canvas.drawBitmap(markerBitmap, point.x, point.y, null);

                canvas.drawPath(path, mPaint);
                //canvas.drawBitmap(bitmap, src, dst, paint);

            }

            public void setPair(GeoPoint gpone, GeoPoint gptwo) {

                gp1 = gpone;
                gp2 = gptwo;

            }

            public void setColor(int clr)
            {
                colr=clr;
            }

            public void setWidth(int w)
            {
                width=w;
            }


        }

Is there anyone to solve my issue ?

回答1:

There are a few things you can do to improve efficiency.

Your first block of code could be made slightly more efficient:

for (int t = 0, size = roads.size(); t < size; t++) { //Avoid calling '.size()' over and over
    for (int i = 0; i < roads.get(t).size() - 1; i++) {//Avoid calling '.size()' over and over
        final GeoPoint road = roads.get(t).get(i); //Reduce the number of get() calls.
        if (boundBox[0] >= road.getLatitudeE6()
            && boundBox[1] >= road.getLongitudeE6()
            && boundBox[2] <= road.getLatitudeE6()
            && boundBox[3] <= road.getLongitudeE6()) {
                MyOverlay mOverlay = new MyOverlay();
                mOverlay.setColor(Color.GREEN);
                mOverlay.setWidth(4);
                mOverlay.setPair(road, roads.get(t).get(i + 1));
                mapOverlays.add(mOverlay);
        }
    }
}

But most importantly, the biggest performance drain I can see in your code is that you are allocating a new rendering objects (Paint, Path, Point) every time draw() is called. This can be refactored so you reuse the same Paint instance:

class MyOverlay extends Overlay {
    GeoPoint gp1 = new GeoPoint(0, 0);
    GeoPoint gp2 = new GeoPoint(0, 0);
    Point p1 = new Point();
    Point p2 = new Point();
    Path path = new Path();
    int colr=0,width=0;

    public MyOverlay() {
          Paint mPaint = new Paint();
          mPaint.setDither(true);
          mPaint.setColor(colr);
          mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
          mPaint.setStrokeJoin(Paint.Join.ROUND);
          mPaint.setStrokeCap(Paint.Cap.ROUND);
          mPaint.setStrokeWidth(width);
    }

      public void draw(Canvas canvas, MapView mapv, boolean shadow) {
          super.draw(canvas, mapv, false);

          path.reset();

          Projection projection = mapv.getProjection();
          projection.toPixels(gp1, p1);
          projection.toPixels(gp2, p2);

          path.moveTo((float) p2.x, (float) p2.y);
          path.lineTo((float) p1.x, (float) p1.y);
          canvas.drawPath(path, mPaint);
      }
  }

For more info see the 'Do's and Dont's section of the article here: http://android-developers.blogspot.com.au/2011/03/android-30-hardware-acceleration.html.

The relevant point from the article is: "Don't create render objects in draw methods: a common mistake is to create a new Paint, or a new Path, every time a rendering method is invoked. This is not only wasteful, forcing the system to run the GC more often, it also bypasses caches and optimizations in the hardware pipeline."