On an OpenStreetMap map with osmDroid and osmBonusPack I display markers and by clicking on it a bubble opens, everything works as I want up to a certain number of markers. The more markers I put on the map, the less responsive the application is. For example with 1000 markers, it takes 6 seconds for the Toolbar menu to appear and as much for moving to another activity such as a simple text display. My code.
private void creationMarker(GeoPoint arg,
String titre,
String proximite,
String description,
String identifiant) {
double doubleProximite;
Marker startMarker = new Marker(map);
startMarker.setPosition(arg);
startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
InfoWindow infoWindow = new MyInfoWindow(R.layout.bonuspack_bubble_black, map);
((MyInfoWindow) infoWindow).setTitre(titre);
((MyInfoWindow) infoWindow).setDescription(description);
((MyInfoWindow) infoWindow).setSubDescription(identifiant);
startMarker.setTitle(((MyInfoWindow) infoWindow).getTitre());
startMarker.setTitle(((MyInfoWindow) infoWindow).getDescription());
startMarker.setTitle(((MyInfoWindow) infoWindow).getSubDescription());
startMarker.setIcon(getResources().getDrawable(R.drawable.croix_verte, null).mutate());
startMarker.setInfoWindow(infoWindow);
doubleProximite = Double.parseDouble(proximite);
Polygon circle = new Polygon();
circle.setPoints(Polygon.pointsAsCircle(arg, doubleProximite));
int myColorZone, myColorCloture;
myColorZone = this.getResources().getColor(R.color.SurfaceZoneActive, getTheme());
circle.setFillColor(myColorZone); // couleur avec arrière plan transparent
myColorCloture = this.getResources().getColor(R.color.ClotureActive, getTheme());
circle.setStrokeColor(myColorCloture);// couleur de la circonférence
circle.setStrokeWidth(3); // épaisseur du trait
map.getOverlays().add(circle);
map.getOverlays().add(startMarker);
}
I use a loop with an SQL database for the marker data.
I guess the more markers there are, the more events the app has to handle. What solutions could solve my problem. Thank you in advance for your answers
A month has passed, I have a solution, I studied the project https://github.com/MKergall/osmbonuspack in the folder
https://github.com/MKergall/osmbonuspack/tree/master/OSMBonusPack/src/main/java/org/osmdroid/bonuspack/clustering there are three files that interested me to manage clustering.
Thanks to M.Kergall and Roman Sidorov who are the creators of these java sources.
I simply copied these files into a test project. I was inspired by the methods that manage Markers in order to put circular Polygons, clustering side it works well, but depending on the zoom level, when the circular polygons are drawn there is no longer any interest in clustering. I countered this problem by managing the drawings of the polygons from the screen, I draw that what there is the screen, ditto for the Markers. Now with 20,000 Markers and Polygons it's just starting to hinder the responsiveness of the application, when before it was around 200. Here are some code snippets below.
Here are some code snippets below.
Main activity code
private void getlireDataBaseMarkers() {
bar.setVisibility(View.VISIBLE);
bar.getLayoutParams().height = 6;
bar.requestLayout();
Thread t = new Thread(){
public void run() {
Bundle messageBundle=new Bundle();
nbrMarker = 0;
dbMarkers = new DBHelper(MainActivity.this);
if (dbMarkers.numberOfRows() == 0) {
return;
}
SQLiteDatabase db = dbMarkers.getReadableDatabase();
Cursor res = db.rawQuery(SqlOrderVisibilite, null);
res.moveToFirst();
int qtyMarkers = dbMarkers.numberOfRows();
bar.setMax(qtyMarkers);
bar.setProgress(0);
MyRadiusMarkerClusterer radiusMarkers = new MyRadiusMarkerClusterer(MainActivity.this);
Double zoom = 15.0;
radiusMarkers.setMaxPolygonZoomLevel(zoom);
GeoPoint lePoint = new GeoPoint(0.0, 0.0, 0.0);
while (!res.isAfterLast() &&
!isPausing.get() &&
isRunning.get()) {
lePoint.setLatitude(res.getDouble(res.getColumnIndex(MARKERS_COLUMN_LATITUDE)));
lePoint.setLongitude(res.getDouble(res.getColumnIndex(MARKERS_COLUMN_LONGITUDE)));
Marker startMarker = new Marker(map);
startMarker.setPosition(lePoint);
startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
startMarker.setIcon(getResources().getDrawable(R.drawable.person, null).mutate());
Polygon circle = new Polygon(map);
int myColorZone, myColorCloture;
circle.setPoints(Polygon.pointsAsCircle(lePoint,getRandomDoubleBetweenRange(20,200)));
myColorZone = MainActivity.this.getResources().getColor(R.color.colorAccent, getTheme());
circle.setFillColor(myColorZone);
myColorCloture = MainActivity.this.getResources().getColor(colorPrimary, getTheme());
circle.getOutlinePaint().setColor(myColorCloture);
circle.getOutlinePaint().setStrokeWidth(4);
radiusMarkers.add(startMarker);
radiusMarkers.add(circle);
nbrMarker++;
myMessage = handler.obtainMessage();
messageBundle.putInt(WRITE_QTY_MARKERS,2); // incrémenter le progress bar
myMessage.setData(messageBundle);
handler.sendMessage(myMessage);
res.moveToNext();
}
map.getOverlays().add(radiusMarkers);
res.close();
dbMarkers.close();
myMessage = handler.obtainMessage();
messageBundle.putInt(WRITE_QTY_MARKERS,1); // afficher le nombre de markers
myMessage.setData(messageBundle);
handler.sendMessage(myMessage);
}
};
isRunning.set(true);
isPausing.set(false);
t.start();
}
part of MyMarkerClusterers code
@Override
public void draw (Canvas canvas, MapView mapView,boolean shadow){
//if zoom has changed and mapView is now stable, rebuild clusters:
// si le zoom a changé et que mapView est maintenant stable, reconstruisez les groupes
Double zoomLevel = mapView.getZoomLevelDouble();
//if (zoomLevel != mLastZoomLevel && !mapView.isAnimating()) {
if (!mapView.isAnimating()) {
mClusters = clusterer(mapView);
pClusters = pclusterer(mapView);
renderer(mClusters, pClusters, canvas, mapView);
setmLastZoomLevel(zoomLevel);
}
for (MyStaticCluster cluster : mClusters) {
cluster.getMarker().draw(canvas, mapView, shadow);
}
for (MyStaticCluster cluster : pClusters) {
if (getmLastZoomLevel() > mMaxPolygonZoomLevel) {
cluster.getPolygon().draw(canvas, mapView, shadow);
}
}
}
part of MyRadiusMarkerClusterer code
@Override
public ArrayList<MyStaticCluster> clusterer(MapView mapView) {
ArrayList<MyStaticCluster> clusters = new ArrayList<>();
convertRadiusToMeters(mapView);
mClonedMarkers = new ArrayList<>(); //shallow copy
ArrayList<Marker> mFiltreMarkers = new ArrayList<>(mItems);
Iterator<Marker> it = mFiltreMarkers.iterator();
while (it.hasNext()){
Marker valeur = it.next();
GeoPoint point = valeur.getPosition();
// limiter le nombre de Marker suivant l'écran
if( mapView.getProjection().getNorthEast().getLatitude() >= point.getLatitude() &&
mapView.getProjection().getNorthEast().getLongitude() >= point.getLongitude() &&
mapView.getProjection().getSouthWest().getLatitude() <= point.getLatitude() &&
mapView.getProjection().getSouthWest().getLongitude() <= point.getLongitude()) {
mClonedMarkers.add(valeur);
}
it.remove();
}
while (!mClonedMarkers.isEmpty()) {
Marker m = mClonedMarkers.get(0);
MyStaticCluster cluster = createCluster(m,null, mapView);
clusters.add(cluster);
}
return clusters;
}
@Override public ArrayList<MyStaticCluster> pclusterer(MapView mapView) {
ArrayList<MyStaticCluster> clusters = new ArrayList<>();
convertRadiusToMeters(mapView);
pClonedPolygon = new ArrayList<> (); //shallow copy
ArrayList<Polygon> pFiltrePolygon = new ArrayList<>(pItems);
Iterator<Polygon> it = pFiltrePolygon.iterator();
while (it.hasNext()){
Polygon valeur = it.next();
GeoPoint point = valeur.getInfoWindowLocation();
// limiter le nombre de Polygon suivant l'écran
if( mapView.getProjection().getNorthEast().getLatitude() >= point.getLatitude() &&
mapView.getProjection().getNorthEast().getLongitude() >= point.getLongitude() &&
mapView.getProjection().getSouthWest().getLatitude() <= point.getLatitude() &&
mapView.getProjection().getSouthWest().getLongitude() <= point.getLongitude()) {
pClonedPolygon.add(valeur);
}
it.remove();
}
while (!pClonedPolygon.isEmpty()) {
Polygon p = pClonedPolygon.get(0);
MyStaticCluster cluster = createCluster(null,p, mapView);
clusters.add(cluster);
}
return clusters;
}