¿Cómo almacenar en caché android.graphics.path o Bitmap cuando se usan Overlays?

Estoy usando una superposición para marcar áreas en Google Maps dibujando una forma de diez miles de GeoPoints que obtengo de cualquier fuente. Esto funciona y se ve así:

@Override public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) { super.draw(canvas, mapView, false); Projection projection = mapView.getProjection(); List<Zone> zones = ApplicationContext.getZones(); path.rewind(); for (Zone zone : zones) { paint.setDither(true); paint.setStyle(Style.FILL); paint.setAlpha(40); MultiPolygon multiPolygon = zone.getMultiPolygon(); List<Polygon> polygons = multiPolygon.getPolygons(); for (Polygon polygon : polygons) { for (List<Coordinate> coordinates : polygon.getCoordinates()) { for (int i = 0; i < coordinates.size(); i++) { Point p = new Point(); projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p); if (i == 0) { path.moveTo(px, py); } else { path.lineTo(px, py); } } } } } canvas.drawPath(path, paint); } 

El problema es que esto es muy consumidor de recursos. Cada vez que se desplaza o mueve el mapa en MapView, la ruta tiene que ser calculada una y otra vez, porque se han cambiado las coordenadas de píxeles. El área dibujada podría llegar a ser tan grande que el desplazamiento en el MapView es tan lento que es funcional inutilizable.

Mis ideas son

  • De alguna manera caché la "forma" que la ruta genera y sólo lo vuelve a dibujar cuando el nivel de zoom cambia en el MapView.
  • Para dibujar de alguna manera la pintura en un "sobre la marcha" -Bitmap para utilizarlo como superposición (tal vez como ItemizedOverlay), escuchar MapView desplazamiento y mover el mapa de bits por la distancia desplazada.

No estoy seguro si hay mejores métodos.

¿Alguna idea de cómo podría solucionar este problema? (Estoy utilizando Google Maps API 1 y no puedo cambiar).

Antes de recurrir a intentar averiguar cómo coincidir con el movimiento del mapa, hay algunas optimizaciones a su código actual que probablemente dará un ahorro significativo. En particular, estas dos líneas dentro de su bucle interno se ejecutan la mayoría de las veces, pero bastante costosas de ejecutar (dos asignaciones de memoria, punto flotante multiplica y cuatro llamadas de método).

 Point p = new Point(); projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p); 

En primer lugar, sólo necesitas un objeto Point , así que evita asignarlo en tu bucle. Muévalo justo debajo de su path.rewind();

En segundo lugar, si pre-calculó sus coordenadas como GeoPoints lugar de calcularlas cada vez, se ahorraría un montón de procesamiento en su rutina de draw . También puede deshacerse de esa declaración if con un poco de trabajo. Suponiendo que usted preconverte su lista de coordinate a una lista de GeoPoint , y la haga disponible a través de polygon.getGeoCoordinates() , podría terminar con sus bucles internos que parecen –

 for (List<GeoPoint> geoCoordinates : polygon.getGeoCoordinates()) { projection.toPixels(geoCoordinates.get(0),p); path.moveTo(px, py); // move to first spot final List<GeoPoint> lineToList = geoCoordinates.sublist(1,geoCoordinates.size()); // A list of all the other points for(GeoPoint gp : lineToList) { projection.toPixels(gp, p); path.lineTo(px, py); } } 

Y eso funcionará mucho más rápido que lo que estabas haciendo antes.

Después de retocar en los últimos días encontré una posible solución (y no creo que haya una mejor) para no dibujar el camino una y otra vez, pero moverlo a la posición actual.

La parte difícil era averiguar cómo guardar en caché la forma dibujada para no calcularla una y otra vez. Esto se puede hacer usando una matriz. Con esta matriz (imagino esto como una especie de "plantilla") puede manipular las coordenadas de puntos dentro de la ruta. La primera vez (cuando alguien comienza a mover el mapa) dibujo el área como de costumbre. Cuando intenta calcularlo por segunda vez o más, no vuelvo a dibujar la forma pero manipulo el camino calculando el "delta" desde el punto actual hasta el último punto. Sé cuál es el punto actual, porque siempre mapeo el GeoPoint original (que siempre permanece igual) hasta el punto que resulta de la proyección actual. El "delta" necesita ser configurado como Matrix. Después de eso transformo el camino usando esta nueva matriz. El resultado es realmente muy rápido. El desplazamiento del mapa es tan rápido como si no se utilizara una superposición.

Esto se parece a esto (esto no es un código de producción, y no puede lidiar con el zoom todavía, pero muestra el principio que utilizo como base para mis optimizaciones):

 public class DistrictOverlay extends Overlay { // private final static String TAG = DistrictOverlay.class.getSimpleName(); private Paint paint = new Paint(); private Path path = new Path(); private boolean alreadyDrawn = false; private GeoPoint origGeoPoint; Point p = new Point(); Point lastPoint = new Point(); @Override public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) { super.draw(canvas, mapView, false); Projection projection = mapView.getProjection(); List<Zone> zones = ApplicationContext.getZones(); if (!alreadyDrawn) { path.rewind(); for (Zone zone : zones) { if (!zone.getZoneId().equals(MenuContext.getChosenZoneId())) { continue; } String dateString = zone.getEffectiveFrom().trim().replace("CEST", "").replace("GMT", "").replace("CET", "").replace("MESZ", ""); if (DateUtil.isBeforeCurrentDate(dateString)) { paint.setColor(Color.RED); } else { paint.setColor(Color.GREEN); } paint.setDither(true); paint.setStyle(Style.FILL); paint.setAlpha(40); MultiPolygon multiPolygon = zone.getMultiPolygon(); List<Polygon> polygons = multiPolygon.getPolygons(); for (Polygon polygon : polygons) { for (List<GeoPoint> geoPoints : polygon.getGeoPoints()) { projection.toPixels(geoPoints.get(0), p); path.moveTo(px, py); origGeoPoint = new GeoPoint(geoPoints.get(0).getLatitudeE6(), geoPoints.get(0).getLongitudeE6()); lastPoint = new Point(px, py); final List<GeoPoint> pathAsList = geoPoints.subList(1, geoPoints.size()); for (GeoPoint geoPoint : pathAsList) { projection.toPixels(geoPoint, p); path.lineTo(px, py); } } } } } else { projection.toPixels(origGeoPoint, p); Matrix translateMatrix = new Matrix(); translateMatrix.setTranslate(px - lastPoint.x, py - lastPoint.y); path.transform(translateMatrix); lastPoint = new Point(px, py); } canvas.drawPath(path, paint); if (!path.isEmpty()) { alreadyDrawn = true; } } @Override public boolean onTap(GeoPoint p, MapView mapView) { return true; } } 
  • Superposición de imagen en dos filas en una vista de lista
  • Superponer un color sobre una vista
  • Superposición de teclas de teclado de Android
  • El desplazamiento y el zoom de MapView es lento después de agregar muchas superposiciones
  • Cómo obtener fechas de la base de datos y comprobar si se solapan?
  • Cabeza de chat Haga clic en eventos
  • Superposición transparente GLSurfaceview en la vista existente en android?
  • Texto que no se muestra en la superposición de MapView
  • Las imágenes transparentes de OpenGL tienen negro en ellas
  • Dibujar texto en la parte superior de mapa de bits no
  • La importación com.android.internal.R no se puede resolver
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.