如果标记数量增加,则应用缓慢



在带有osmDroid和osmBonusPack的OpenStreetMap地图上,我显示标记,通过单击它打开一个气泡,一切都可以按照我想要的方式工作,最多一定数量的标记。 我在地图上放置的标记越多,应用程序的响应就越慢。 例如,对于 1000 个标记,工具栏菜单的显示需要 6 秒,移动到另一个活动(如简单文本显示(也需要 6 秒。 我的代码。

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);
}

我对标记数据使用带有 SQL 数据库的循环。

我想标记越多,应用程序必须处理的事件就越多。 什么解决方案可以解决我的问题。 提前感谢您的回答

标记是相当重量级的,或者至少在一段时间前,当我遇到与您类似的性能问题时。可能会有优化它们的潜力,但这意味着修改 Osmdroid 库并创建包含此类更改的拉取请求。

尝试执行一些分析,以确保问题不在代码中,而是在库 (https://developer.android.com/studio/profile/cpu-profiler.html( 中。

注意如何从 databse 读取数据 - 不要在主线程上执行此操作,并测量确保它不是主要问题所需的时间。

尝试来自Osmdrid的SimpleFastPointOverlay - 它应该针对更多数量的标记进行优化(尽管它们必须具有相同的图标(。即使它不够灵活,可以满足您的需求,请尝试验证标记是真正的问题。之后,您可以查看源代码并将其用作学习材料来实现您自己的自定义覆盖。

一个月过去了,我有一个解决方案,我在文件夹中研究了 https://github.com/MKergall/osmbonuspack 的项目

https://github.com/MKergall/osmbonuspack/tree/master/OSMBonusPack/src/main/java/org/osmdroid/bonuspack/clustering 有三个文件让我对管理群集感兴趣。

  • 标记群集器.java
  • RadiusMarkerClusterer.java
  • 静态集群.java

感谢M.Kergall和Roman Sidorov,他们是这些java源代码的创建者。

我只是将这些文件复制到测试项目中。我的灵感来自管理标记以放置圆形多边形的方法,聚类侧效果很好,但根据缩放级别,当绘制圆形多边形时,对聚类不再感兴趣。我通过管理屏幕上多边形的绘图来解决这个问题,我绘制屏幕,标记也是如此。现在有 20,000 个标记和多边形,它才刚刚开始阻碍应用程序的响应能力,而以前大约有 200 个。下面是一些代码片段。

下面是一些代码片段。
主活动代码

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();
}

MyMarkerClusterers 代码的一部分

@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);
}
}
}

MyRadiusMarkerClusterer 代码的一部分

@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;
}

最新更新