Java 在Android上向GoogleMap添加大型GeoJson的有效方法

Java 在Android上向GoogleMap添加大型GeoJson的有效方法,java,android,google-maps,geojson,Java,Android,Google Maps,Geojson,我有一张3公里网格区域的温度图。 也就是说,我有几千个有颜色的多边形 我试图在我的kotlin应用程序中,在android上的谷歌地图上显示它们 问题是我需要在UI线程中添加GeoJson层,这需要8-15秒。也就是说,申请一直处于冻结状态 关于StackOverflow这个问题有很多老的答案,但它们都与我无关: 他们建议减少json——我已经用相同的值从附近的正方形创建了集群 他们建议使用MapView和覆盖,但在最新的google map API中,没有MapView和在后台线程中添加覆盖的

我有一张3公里网格区域的温度图。 也就是说,我有几千个有颜色的多边形

我试图在我的kotlin应用程序中,在android上的谷歌地图上显示它们

问题是我需要在UI线程中添加GeoJson层,这需要8-15秒。也就是说,申请一直处于冻结状态

关于StackOverflow这个问题有很多老的答案,但它们都与我无关:

  • 他们建议减少json——我已经用相同的值从附近的正方形创建了集群
  • 他们建议使用MapView和覆盖,但在最新的google map API中,没有MapView和在后台线程中添加覆盖的功能
  • 我试过:

  • map.addPolygon,而不是创建GeoJsonLayer
  • 地图添加覆盖与地面覆盖
  • 当UI被冻结时,我仍然或多或少有相同的时间


    我如何处理这个问题?有没有办法从背景线程中的数千个彩色矩形创建地图,然后立即在UI线程中显示它?

    如果您已经尝试了
    addPolygon()
    GroundOverlay
    ,还有两种可能:

  • 使用(首选)

  • 使用自定义绘图覆盖或

  • 由于高性能实现的可能性,IMHO平铺覆盖是一种更好的方法。例如,您可以为“低”缩放级别和“当前”(应该在开始时显示给用户的级别)缩放级别创建分幅,并将它们存储在数组(
    HashMap
    等)或文件系统路径
    。\zoom\u level\x\y\tile.png
    中(如果有很多分幅)。当需要显示时,您可以“动态”(在单独的线程中)创建更“详细”的平铺,然后还可以存储它们以备将来使用(如果需要)。当然,您需要定制模块来进行快速
    GeoJson
    读取(类似Jackson)并将其渲染到
    .png
    平铺中。因此,似乎可以为您的案例创建
    TileProvider
    ,以优化性能和内存消耗。您可以使用作为第一次迭代

    如果选择自定义图形,则应为
    MapView
    覆盖
    onDraw()
    方法,或为
    MapFragment
    覆盖
    dispatchDraw()
    。比如说。在这种情况下,您可以控制整个流程,但这种方式对于实现来说更为复杂

    更新:

    您可以为
    onCameraMove()
    执行操作,如在answer中(此处使用的
    GoogleMap
    对象的一些复杂传递):

    更新#2:

    您可以制作多边形当前视图的“屏幕截图”(不完全是屏幕截图,但在位图上创建多边形的图像),并将其移动到
    onCameraMove()
    (而不是重新绘制所有多边形)。然后在
    onCameraIdle()
    中创建并显示新的完整多边形视图。此外,您还可以创建比地图屏幕视图稍大的位图(用于正确缩小和滚动)。或者,您可以“跳过”一些
    onCameraMove()
    调用(例如,每3次调用
    onCameraMove()
    调用一次)


    顺便说一句:如果是平铺覆盖,可以“从框中”移动和缩放。您只需要创建一个复杂的TileProvider。整个设备屏幕只需要生成几个磁贴(单个磁贴的大小为256x256)。因此,您可以为当前屏幕、currentZoomLevel-1、currentZoomLevel+1(缩放时)和+2(或3)生成左、右、上和下(滚动时)的分幅。此外,您还可以将生成的磁贴存储在某些缓存(HashMap、LRU等)中,以备将来使用。您可以生成“额外”(当前不可见)在单独的线程中平铺。

    我建议不要一次创建这几千个多边形,因为这会影响时间和性能,但是您可以使用GoogleMap.OnCameraMoveListener和GoogleMap.onCameradleListener动态创建所示位置附近的多边形

    编辑:- “动态显示位置附近的多边形”我的意思是只创建用户当前看到的多边形,即在地图的当前可见区域边界内:-您可以通过

    googleMap.projection.visibleRegion.latLngBounds
    
    “GoogleMap.OnCameraMoveListener和GoogleMap.OnCameraDelListenerWhat”,我的意思是这里有两种方法,首先,当用户停止滚动地图“SetOnCameraDelListener”时,用可见边界内的多边形更新地图第二种方法是使用setOnCameraMoveStartedListener,在用户每次开始滚动地图时,使用可见边界内的多边形更新地图

     override fun onMapReady(googleMap: GoogleMap?) {
            googleMap ?: return
            with(googleMap) {
                setMinZoomPreference(9f)
                setOnCameraIdleListener {
                 // first approach user stopped scrolling so update the map with polygons within the boundaries 
                }
                setOnCameraMoveStartedListener {
                 // second approach user started scrolling so update the map with polygons within the boundaries 
                }
            }
    

    这可能会有所帮助:@kalabalik,正如我所描述的,这不是我的问题。我可以在后台准备数据谢谢!从geojson创建不同缩放级别的平铺看起来工作量太大,但我将尝试第二种方法!看起来不错,但是在地图移动时不调用dispatchDraw,所以当我移动或缩放地图时,我的多边形将保留在同一位置map@PavelBernshtam请参阅更新的答案。简单地说:您可以在
    public void onCameraMove()
    中调用自定义视图的
    invalidate()
    来完成此操作。谢谢,但它的工作非常不平稳。即,在地图更改位置后,我的多边形正在缓慢移动(!)。非常不愉快的用户体验…@PavelBernshtam请参阅更新#2。请解释更多,它是什么意思“在飞行中靠近显示位置的多边形”以及我将如何使用GoogleMap.OnCameraMoveListener和GoogleMap.OnCameraDelListener?请注意,我更新了我的答案。希望能对你有所帮助。我不确定这是否与我的情况有关,因为当所有多边形都应该可见时,我从缩小开始,但我会尝试。非常感谢。
     override fun onMapReady(googleMap: GoogleMap?) {
            googleMap ?: return
            with(googleMap) {
                setMinZoomPreference(9f)
                setOnCameraIdleListener {
                 // first approach user stopped scrolling so update the map with polygons within the boundaries 
                }
                setOnCameraMoveStartedListener {
                 // second approach user started scrolling so update the map with polygons within the boundaries 
                }
            }