HarmonyOS鸿蒙Next中【高德地图】动态绘制大量marker耦合问题、性能优化初步解决方案(使用MapKit也可参考)

HarmonyOS鸿蒙Next中【高德地图】动态绘制大量marker耦合问题、性能优化初步解决方案(使用MapKit也可参考) 对于地图功能丰富的项目,有绘制不同样式Marker的需求,而且很多时候不是固定图标,而是需要动态绘制。

目前能找到的办法就是通过componentSnapshot截图来实现动态绘制Marker,

然而componentSnapshot不支持全局builder,很多小伙伴初步接触鸿蒙,只能把绘制Marker的builder方法放到业务组件或者页面中,

这样增加了代码的耦合性,还无法复用。

这时可以尝试这样的思路:

写一个mapController类管理地图,生成marker的时候,用外部传入的一个builder方法。这个buider方法需要在某个组件实现并传入,实现builder的时候还可以直接调用单独封装的自定义组件。

// MapController:

stationMarkerBuilder?: (station:MapStationListBean) => void
...
let pixmap = await componentSnapshot.createFromBuilder(()=>{if (this.stationMarkerBuilder)this.stationMarkerBuilder(item)})

// MapPage:
this.mapController.stationMarkerBuilder = 
(station) => { this.stationBuilder(station) }
...
  @Builder
  stationBuilder(station:MapStationListBean) {
    MapStationMarkerView({num:station.stationNum})
  }

耦合的问题解决了。但实际调试我们还会发现,这样实时的绘制,在Marker比较多的情况下,性能很差

每次绘制要300-500ms,当动态内容很多,每次绘制几十上百个marker,顺序绘制的话要好几秒,效果很差劲。

这时可以尝试将异步并发绘制,再更进一步将代码拆分,

在上面代码的基础上,把单独封装marker对象,把业务数据、marker配置、builder方法都放进去,生成的图片也存在这里,这样有更多优化空间。

export class LineMapStationMarkerObj {

  stationBean:MapStationListBean
  option?:MarkerOptions
  icon?:BitmapDescriptor

  stationMarkerBuilder?: (station:MapStationListBean) => void

  constructor(station:MapStationListBean) {
    this.stationBean = station
  }

  async updateOption() {

    let latitude = Number(this.stationBean.latitude)
    let longitude = Number(this.stationBean.longitude)
    if (latitude && longitude) {
      let option: MarkerOptions = new MarkerOptions();

      if (!this.icon) {
        console.time('componentSnapshotStation')
        let pixmap = await componentSnapshot.createFromBuilder(() => {
          if (this.stationMarkerBuilder) this.stationMarkerBuilder(this.stationBean)
        }) //, 320, true, {scale : 2, waitUntilRenderFinished : true})
        console.timeEnd('componentSnapshotStation')
        //
        this.icon = BitmapDescriptorFactory.fromPixelMapSync(pixmap)
      }

      if (this.icon) {
        option.setIcon(this.icon);
      }
      option.setDraggable(false);
      option.setPosition(new LatLng(latitude, longitude));
      option.setAnchor(0.5, 1);
      this.option = option
    }
  }
}

// MapController:
  // 重新绘制站点marker
  async redrawStationMarkers(data:MapStationListBean[]) {
    this.stationList = data
    if (!this.aMap) {
      return
    }
    // 清除之前的
    this.stationMarkers?.forEach((marker)=>{
      this.aMap?.removeOverlay(marker.getId())
    })

        // 整理数据、marker设置
    let stationMarkerObjs : LineMapStationMarkerObj[] = []
    let promiseList : Promise<void>[] = [] // 异步任务

    data.forEach((item) => {
      let markerObj = new LineMapStationMarkerObj(item)
      markerObj.stationMarkerBuilder = this.stationMarkerBuilder
      stationMarkerObjs.push(markerObj)
      // 添加异步任务
      promiseList.push(markerObj.updateOption())
    })
    this.stationMarkerObjs = stationMarkerObjs

    // 并发异步获取option
    Promise.all(promiseList).then(()=>{
      let optionsList :ArrayList<MarkerOptions> = new ArrayList<MarkerOptions>()
      this.stationMarkerObjs?.forEach((markerObj) => {
        optionsList.add(markerObj.option)
      })
      this.stationMarkers = this.aMap?.addMarkers(optionsList)
    })
  }

优化到这一步,效果还可以接受~

如果小伙伴们有更好、更进一步的方案,欢迎评论分享~


更多关于HarmonyOS鸿蒙Next中【高德地图】动态绘制大量marker耦合问题、性能优化初步解决方案(使用MapKit也可参考)的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中【高德地图】动态绘制大量marker耦合问题、性能优化初步解决方案(使用MapKit也可参考)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,动态绘制大量marker时,可能会遇到性能瓶颈和耦合问题。初步解决方案包括:

  • 批量绘制:使用MarkerOptions批量添加marker,减少频繁调用导致的性能损耗。
  • 对象池复用:通过对象池管理marker,避免频繁创建和销毁对象,提升性能。
  • 异步处理:将marker的绘制操作放在子线程中执行,避免阻塞主线程。
  • 数据分页:按需加载marker数据,减少一次性绘制过多marker的压力。
  • 简化UI:优化marker的图标和动画,减少渲染复杂度。

这些方法同样适用于使用MapKit的场景,能有效提升性能并降低耦合度。

回到顶部