You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Map自定义URL标记加载缓慢:求实现即时加载的优化方案

Google Map自定义标记加载缓慢优化方案

问题描述

尽管使用极小图标,Google Map上的自定义标记仍需约10秒加载完成,推测加载调用方式存在问题,希望实现近乎即时加载,目标是让标记一次性全部加载。


初始代码(加载缓慢版本)

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:custom_marker/marker_icon.dart';
import '../../models/marker_collect_model.dart';

class PhotoCustomMap extends StatefulWidget {
  @override
  _PhotoCustomMapState createState() => _PhotoCustomMapState();
}

class _PhotoCustomMapState extends State<PhotoCustomMap> {
  List<Marker> list = [];
  List<String> listDocuments = [];

  Future<void> readDataFromFirebase() async {
    await Firebase.initializeApp();
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    CollectionReference<Map<String, dynamic>> collectionReference =
    firestore.collection('NWNSPHOTOS2023');
    collectionReference.snapshots().listen((event) async {
      List<DocumentSnapshot> snapshots = event.docs;
      for (var map in snapshots) {
        Map<String, dynamic> data =
        map.data() as Map<String, dynamic>;
        MarkerCollectModel model =
        MarkerCollectModel.fromMap(data);
        String nameDocument = map.id;
        listDocuments.add(nameDocument);
        Marker marker = await createMarker(model, nameDocument);
        setState(() {
          list.add(marker);
        });
      }
    });
  }

  Future<Marker> createMarker(
      MarkerCollectModel markerCollectModel, String nameDocument) async {

    BitmapDescriptor bitmapDescriptor = await MarkerIcon.downloadResizePictureCircle(
        markerCollectModel.pathImageSmall!,
        addBorder: true,
        borderColor: Colors.blue,
        borderSize: 5,
        size: 50
    );

    Marker marker;
    marker = Marker(
      markerId: MarkerId(nameDocument),
      position: LatLng(markerCollectModel.lat!, markerCollectModel.lng!),
      icon: bitmapDescriptor,
    );
    return marker;
  }

  Set<Marker> myMarkers() {
    return list.toSet();
  }

  @override
  void initState() {
    super.initState();
    readDataFromFirebase();
  }

  @override
  Widget build(BuildContext context) {
    WidgetsFlutterBinding.ensureInitialized();
    Firebase.initializeApp();
    CameraPosition cameraPosition =
    CameraPosition(target: LatLng(47.088717, -122.496509), zoom: 7.7);
    return Scaffold(
        body: Center(
            child: Stack(
              children: <Widget>[
                GoogleMap(
                  initialCameraPosition: cameraPosition,
                  markers: myMarkers(),
                ),
              ],
            )));
  }
}

优化后的代码(即时加载版本)

import 'dart:async';
import 'dart:ui';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:rideyrbiketracker/pages/screens/DetailScreen.dart';

import '../../models/marker_collect_model.dart';

class PhotoMap extends StatefulWidget {
  @override
  _PhotoMapState createState() => _PhotoMapState();
}

class _PhotoMapState extends State<PhotoMap> {
  GoogleMapController? controller;
  Set<Polyline> _polylines = {};
  bool imagetapped = false;
  List<Marker> list = [];
  List<String> listDocuments = [];

  Future<void> readDataFromFirebase() async {
    await Firebase.initializeApp();
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    CollectionReference<Map<String, dynamic>> collectionReference =
    firestore.collection('NWNSPHOTOS2023');

    List<Marker> markers = [];
    List<String> documents = [];
    (await collectionReference.get()).docs.forEach((doc) async {
      Map<String, dynamic> data = doc.data();
      MarkerCollectModel model = MarkerCollectModel.fromMap(data);
      String nameDocument = doc.id;

        final markerImageFile = (await DefaultCacheManager()
            .getSingleFile(model.pathImageSmall!));
        final Uint8List bytes = await markerImageFile.readAsBytes();

        final Codec markerImageCodec = await instantiateImageCodec(
            bytes,
            targetHeight: 50,
            targetWidth: 50
        );

        final FrameInfo frameInfo = await markerImageCodec.getNextFrame();

        final ByteData? byteData = await frameInfo.image.toByteData(
          format: ImageByteFormat.png,
        );

        final Uint8List resizedMarkerImageBytes = byteData!.buffer.asUint8List();

        BitmapDescriptor _bitmapDescriptor = BitmapDescriptor.fromBytes(resizedMarkerImageBytes, size: Size(50, 50));

        markers.add(Marker(
          markerId: MarkerId(nameDocument),
          position: LatLng(model.lat!, model.lng!),
          icon: _bitmapDescriptor,
          onTap: () {
            MaterialPageRoute route = MaterialPageRoute(
              builder: (context) => DetailScreener(model),
            );
            Navigator.push(context, route);
          },
          infoWindow: InfoWindow(
            title: model.name! +
                " | | " +
                "MILE: " +
                model.mileager!,
            snippet: '${model.dateTime}',
            onTap: () {
              MaterialPageRoute route = MaterialPageRoute(
                builder: (context) => DetailScreener(model),
              );
              Navigator.push(context, route);
            },
          ),
        ));

        setState(() {
          list = markers;
          listDocuments = documents;
        });
      });
  }

  Set<Marker> myMarkers() {
    return list.toSet();
  }

  @override
  void initState() {
    super.initState();

    const oneSec = Duration(seconds:15);
    readDataFromFirebase();
    Timer.periodic(oneSec, (Timer t) =>
        readDataFromFirebase());
  }
  
  @override
  Widget build(BuildContext context) {
    WidgetsFlutterBinding.ensureInitialized();
    Firebase.initializeApp();
    CameraPosition cameraPosition =
        CameraPosition(target: LatLng(47.088717, -122.496509), zoom: 7.7);
    return Scaffold(
        body: Center(
            child: Stack(
      children: <Widget>[
        GoogleMap(
          initialCameraPosition: cameraPosition,
          markers: myMarkers(),
          polylines: _polylines,
        ),
      ],
    )));
  }
}

核心优化点说明

  • 批量更新UI:初始版本每创建一个标记就调用setState触发重绘,优化后先将所有标记存入临时列表,完成后一次性更新UI,大幅减少重绘次数。
  • 原生图片处理:移除第三方custom_marker库,改用Flutter原生instantiateImageCodec处理图片缩放,提升处理效率。
  • 图片缓存机制:引入flutter_cache_manager缓存图片文件,避免重复下载,加速后续加载速度。
  • 一次性数据获取:将实时监听snapshots().listen改为一次性get()获取所有文档,批量处理标记创建,避免逐个处理的延迟。
  • 定时刷新数据:添加15秒周期的定时刷新,确保标记数据能及时同步Firestore的更新。

内容的提问来源于stack exchange,提问作者giroprotagonist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 07:14:58