如果标记数量增加,应用程序会变慢

Slow application if the number of Markers increases

在带有 osmDroid 和 osmBonusPack 的 OpenStreetMap 地图上,我显示标记并通过单击它打开一个气泡,一切正常,因为我想要达到一定数量的标记。 我在地图上放置的标记越多,应用程序的响应就越慢。 例如,对于 1000 个标记,工具栏菜单出现需要 6 秒,移动到另一个 activity(例如简单文本显示)也需要同样多的时间。 我的代码。

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)。

注意您如何从数据库中读取数据 - 不要在主线程上执行并测量需要多长时间以确保它不是主要问题。

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

一个月过去了,我有办法了,我研究了文件夹https://github.com/MKergall/osmbonuspack中的项目

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

  • MarkerClusterer.java
  • 半径MarkerClusterer.java
  • StaticCluster.java

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

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

下面是一些代码片段。
主要activity代码

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