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
相关产品推荐
相关产品推荐

