Skip to content

Commit e113fdd

Browse files
authored
fix: initialize view listeners on platform view creation (#342)
Make sure view event listeners are initialized as soon as view is created to avoid missing early view events.
1 parent 9087fed commit e113fdd

21 files changed

+118
-56
lines changed

android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsAutoViewMessageHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,8 @@ class GoogleMapsAutoViewMessageHandler(private val viewRegistry: GoogleMapsViewR
378378
getView().clearCircles()
379379
}
380380

381-
override fun registerOnCameraChangedListener() {
382-
getView().registerOnCameraChangedListener()
381+
override fun enableOnCameraChangedEvents() {
382+
getView().enableOnCameraChangedEvents()
383383
}
384384

385385
override fun isAutoScreenAvailable(): Boolean {

android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsBaseMapView.kt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ abstract class GoogleMapsBaseMapView(
5959

6060
// Nullable variable to hold the callback function
6161
private var _mapReadyCallback: ((Result<Unit>) -> Unit)? = null
62-
private var _loadedCallbackPending = false
62+
private var _pendingCameraEventsListenerSetup = false
6363

6464
/// Default values for UI features.
6565
private var _consumeMyLocationButtonClickEventsEnabled: Boolean = false
@@ -212,6 +212,10 @@ abstract class GoogleMapsBaseMapView(
212212
}
213213
}
214214
)
215+
216+
if (_pendingCameraEventsListenerSetup) {
217+
setOnCameraChangedListeners()
218+
}
215219
}
216220

217221
// Installs a custom invalidator for the map view.
@@ -910,7 +914,17 @@ abstract class GoogleMapsBaseMapView(
910914
_circles.clear()
911915
}
912916

913-
fun registerOnCameraChangedListener() {
917+
fun enableOnCameraChangedEvents() {
918+
// If map is already initialized, set the listeners.
919+
// Otherwise, the listeners will be set in the initListeners method.
920+
if (_map != null) {
921+
setOnCameraChangedListeners()
922+
} else {
923+
_pendingCameraEventsListenerSetup = true
924+
}
925+
}
926+
927+
fun setOnCameraChangedListeners() {
914928
getMap().setOnCameraMoveStartedListener { reason ->
915929
val event =
916930
when (reason) {
@@ -943,6 +957,7 @@ abstract class GoogleMapsBaseMapView(
943957
position,
944958
) {}
945959
}
960+
_pendingCameraEventsListenerSetup = false
946961
}
947962

948963
fun setPadding(padding: MapPaddingDto) {

android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsViewMessageHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,8 @@ class GoogleMapsViewMessageHandler(private val viewRegistry: GoogleMapsViewRegis
488488
getView(viewId.toInt()).clearCircles()
489489
}
490490

491-
override fun registerOnCameraChangedListener(viewId: Long) {
492-
getView(viewId.toInt()).registerOnCameraChangedListener()
491+
override fun enableOnCameraChangedEvents(viewId: Long) {
492+
getView(viewId.toInt()).enableOnCameraChangedEvents()
493493
}
494494

495495
override fun setPadding(viewId: Long, padding: MapPaddingDto) {

android/src/main/kotlin/com/google/maps/flutter/navigation/ImageRegistry.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class ImageRegistry {
2727

2828
private var isMapViewInitialized = false
2929

30+
// BitmapDescriptor cannot be created if map view is not initialized yet.
31+
// When map view is initialized, all queued bitmaps are processed and added to the registry.
3032
fun mapViewInitializationComplete() {
3133
isMapViewInitialized = true
3234
bitmapQueue.forEach {
@@ -47,7 +49,7 @@ class ImageRegistry {
4749
val bitmap = createBitmap(bytes, imagePixelRatio, density, width, height)
4850

4951
if (!isMapViewInitialized) {
50-
// BitmapDescriptor cannot me created if map view is not initialized yet.
52+
// BitmapDescriptor cannot be created if map view is not initialized yet.
5153
// Add to queue to make it later.
5254
bitmapQueue.add(QueuedBitmap(imageId, bitmap, imagePixelRatio, width, height))
5355
} else {

android/src/main/kotlin/com/google/maps/flutter/navigation/messages.g.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2230,7 +2230,7 @@ interface MapViewApi {
22302230

22312231
fun clearCircles(viewId: Long)
22322232

2233-
fun registerOnCameraChangedListener(viewId: Long)
2233+
fun enableOnCameraChangedEvents(viewId: Long)
22342234

22352235
fun setPadding(viewId: Long, padding: MapPaddingDto)
22362236

@@ -4522,7 +4522,7 @@ interface MapViewApi {
45224522
val channel =
45234523
BasicMessageChannel<Any?>(
45244524
binaryMessenger,
4525-
"dev.flutter.pigeon.google_navigation_flutter.MapViewApi.registerOnCameraChangedListener",
4525+
"dev.flutter.pigeon.google_navigation_flutter.MapViewApi.enableOnCameraChangedEvents",
45264526
codec,
45274527
)
45284528
if (api != null) {
@@ -4531,7 +4531,7 @@ interface MapViewApi {
45314531
val viewIdArg = args[0].let { if (it is Int) it.toLong() else it as Long }
45324532
var wrapped: List<Any?>
45334533
try {
4534-
api.registerOnCameraChangedListener(viewIdArg)
4534+
api.enableOnCameraChangedEvents(viewIdArg)
45354535
wrapped = listOf<Any?>(null)
45364536
} catch (exception: Throwable) {
45374537
wrapped = wrapError(exception)
@@ -6630,7 +6630,7 @@ interface AutoMapViewApi {
66306630

66316631
fun clearCircles()
66326632

6633-
fun registerOnCameraChangedListener()
6633+
fun enableOnCameraChangedEvents()
66346634

66356635
fun isAutoScreenAvailable(): Boolean
66366636

@@ -8297,14 +8297,14 @@ interface AutoMapViewApi {
82978297
val channel =
82988298
BasicMessageChannel<Any?>(
82998299
binaryMessenger,
8300-
"dev.flutter.pigeon.google_navigation_flutter.AutoMapViewApi.registerOnCameraChangedListener",
8300+
"dev.flutter.pigeon.google_navigation_flutter.AutoMapViewApi.enableOnCameraChangedEvents",
83018301
codec,
83028302
)
83038303
if (api != null) {
83048304
channel.setMessageHandler { _, reply ->
83058305
var wrapped: List<Any?>
83068306
try {
8307-
api.registerOnCameraChangedListener()
8307+
api.enableOnCameraChangedEvents()
83088308
wrapped = listOf<Any?>(null)
83098309
} catch (exception: Throwable) {
83108310
wrapped = wrapError(exception)

example/lib/pages/navigation.dart

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,12 +1405,14 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
14051405
ElevatedButton(
14061406
onPressed: _pauseSimulation,
14071407
child: const Text('Pause simulation'),
1408-
),
1409-
if (_simulationState == SimulationState.paused)
1408+
)
1409+
else if (_simulationState == SimulationState.paused)
14101410
ElevatedButton(
14111411
onPressed: _resumeSimulation,
14121412
child: const Text('Resume simulation'),
1413-
),
1413+
)
1414+
else
1415+
Text(_simulationState.description),
14141416
],
14151417
),
14161418
const SizedBox(height: 10)
@@ -1771,3 +1773,21 @@ class _NavigationPageState extends ExamplePageState<NavigationPage> {
17711773
}
17721774
}
17731775
}
1776+
1777+
/// Returns a human-readable description of the [SimulationState].
1778+
extension SimulationStateDescription on SimulationState {
1779+
String get description {
1780+
switch (this) {
1781+
case SimulationState.unknown:
1782+
return 'Unknown simulation state';
1783+
case SimulationState.running:
1784+
return 'Running';
1785+
case SimulationState.runningOutdated:
1786+
return 'Running with outdated route';
1787+
case SimulationState.paused:
1788+
return 'Paused';
1789+
case SimulationState.notRunning:
1790+
return 'Not running';
1791+
}
1792+
}
1793+
}

ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsAutoViewMessageHandler.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,8 @@ class GoogleMapsAutoViewMessageHandler: AutoMapViewApi {
464464
try getView().setMaxZoomPreference(maxZoomPreference: Float(maxZoomPreference))
465465
}
466466

467-
func registerOnCameraChangedListener() throws {
468-
try getView().registerOnCameraChangedListener()
467+
func enableOnCameraChangedEvents() throws {
468+
try getView().enableOnCameraChangedEvents()
469469
}
470470

471471
func isAutoScreenAvailable() throws -> Bool {

ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ public class GoogleMapsNavigationView: NSObject, FlutterPlatformView, ViewSettle
868868
_consumeMyLocationButtonClickEventsEnabled
869869
}
870870

871-
func registerOnCameraChangedListener() {
871+
func enableOnCameraChangedEvents() {
872872
// Camera listeners cannot be controlled at runtime, so use this
873873
// boolean to control if camera changes are sent over the event channel.
874874
_listenCameraChanges = true

ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationViewMessageHandler.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,8 @@ class GoogleMapsNavigationViewMessageHandler: MapViewApi {
548548
try getView(viewId).setMaxZoomPreference(maxZoomPreference: Float(maxZoomPreference))
549549
}
550550

551-
func registerOnCameraChangedListener(viewId: Int64) throws {
552-
try getView(viewId).registerOnCameraChangedListener()
551+
func enableOnCameraChangedEvents(viewId: Int64) throws {
552+
try getView(viewId).enableOnCameraChangedEvents()
553553
}
554554

555555
func setPadding(viewId: Int64, padding: MapPaddingDto) throws {

ios/google_navigation_flutter/Sources/google_navigation_flutter/messages.g.swift

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,7 +2042,7 @@ protocol MapViewApi {
20422042
func updateCircles(viewId: Int64, circles: [CircleDto]) throws -> [CircleDto]
20432043
func removeCircles(viewId: Int64, circles: [CircleDto]) throws
20442044
func clearCircles(viewId: Int64) throws
2045-
func registerOnCameraChangedListener(viewId: Int64) throws
2045+
func enableOnCameraChangedEvents(viewId: Int64) throws
20462046
func setPadding(viewId: Int64, padding: MapPaddingDto) throws
20472047
func getPadding(viewId: Int64) throws -> MapPaddingDto
20482048
}
@@ -3761,23 +3761,22 @@ class MapViewApiSetup {
37613761
} else {
37623762
clearCirclesChannel.setMessageHandler(nil)
37633763
}
3764-
let registerOnCameraChangedListenerChannel = FlutterBasicMessageChannel(
3765-
name:
3766-
"dev.flutter.pigeon.google_navigation_flutter.MapViewApi.registerOnCameraChangedListener",
3764+
let enableOnCameraChangedEventsChannel = FlutterBasicMessageChannel(
3765+
name: "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.enableOnCameraChangedEvents",
37673766
binaryMessenger: binaryMessenger, codec: codec)
37683767
if let api = api {
3769-
registerOnCameraChangedListenerChannel.setMessageHandler { message, reply in
3768+
enableOnCameraChangedEventsChannel.setMessageHandler { message, reply in
37703769
let args = message as! [Any?]
37713770
let viewIdArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32)
37723771
do {
3773-
try api.registerOnCameraChangedListener(viewId: viewIdArg)
3772+
try api.enableOnCameraChangedEvents(viewId: viewIdArg)
37743773
reply(wrapResult(nil))
37753774
} catch {
37763775
reply(wrapError(error))
37773776
}
37783777
}
37793778
} else {
3780-
registerOnCameraChangedListenerChannel.setMessageHandler(nil)
3779+
enableOnCameraChangedEventsChannel.setMessageHandler(nil)
37813780
}
37823781
let setPaddingChannel = FlutterBasicMessageChannel(
37833782
name: "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setPadding",
@@ -5630,7 +5629,7 @@ protocol AutoMapViewApi {
56305629
func updateCircles(circles: [CircleDto]) throws -> [CircleDto]
56315630
func removeCircles(circles: [CircleDto]) throws
56325631
func clearCircles() throws
5633-
func registerOnCameraChangedListener() throws
5632+
func enableOnCameraChangedEvents() throws
56345633
func isAutoScreenAvailable() throws -> Bool
56355634
func setPadding(padding: MapPaddingDto) throws
56365635
func getPadding() throws -> MapPaddingDto
@@ -6855,21 +6854,21 @@ class AutoMapViewApiSetup {
68556854
} else {
68566855
clearCirclesChannel.setMessageHandler(nil)
68576856
}
6858-
let registerOnCameraChangedListenerChannel = FlutterBasicMessageChannel(
6857+
let enableOnCameraChangedEventsChannel = FlutterBasicMessageChannel(
68596858
name:
6860-
"dev.flutter.pigeon.google_navigation_flutter.AutoMapViewApi.registerOnCameraChangedListener",
6859+
"dev.flutter.pigeon.google_navigation_flutter.AutoMapViewApi.enableOnCameraChangedEvents",
68616860
binaryMessenger: binaryMessenger, codec: codec)
68626861
if let api = api {
6863-
registerOnCameraChangedListenerChannel.setMessageHandler { _, reply in
6862+
enableOnCameraChangedEventsChannel.setMessageHandler { _, reply in
68646863
do {
6865-
try api.registerOnCameraChangedListener()
6864+
try api.enableOnCameraChangedEvents()
68666865
reply(wrapResult(nil))
68676866
} catch {
68686867
reply(wrapError(error))
68696868
}
68706869
}
68716870
} else {
6872-
registerOnCameraChangedListenerChannel.setMessageHandler(nil)
6871+
enableOnCameraChangedEventsChannel.setMessageHandler(nil)
68736872
}
68746873
let isAutoScreenAvailableChannel = FlutterBasicMessageChannel(
68756874
name: "dev.flutter.pigeon.google_navigation_flutter.AutoMapViewApi.isAutoScreenAvailable",

lib/src/google_maps_map_view.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ abstract class MapViewState<T extends GoogleMapsBaseMapView> extends State<T> {
360360
widget.onCameraMove != null ||
361361
widget.onCameraIdle != null) {
362362
GoogleMapsNavigationPlatform.instance.viewAPI
363-
.registerOnCameraChangedListener(viewId: viewId);
363+
.enableOnCameraChangedEvents(viewId: viewId);
364364
}
365365
GoogleMapsNavigationPlatform.instance.viewAPI
366366
.getCameraChangedEventStream(viewId: viewId)
@@ -412,13 +412,17 @@ class GoogleMapsMapViewState extends MapViewState<GoogleMapsMapView> {
412412
padding: widget.initialPadding,
413413
),
414414
),
415-
onMapReady: _onPlatformViewCreated);
415+
onPlatformViewCreated: _onPlatformViewCreated,
416+
onMapReady: _onMapReady);
416417
}
417418

418-
/// Callback method when platform view is created.
419+
/// Callback method for platform view is created event.
419420
void _onPlatformViewCreated(int viewId) {
420421
initMapViewListeners(viewId);
422+
}
421423

424+
/// Callback method for map ready event.
425+
void _onMapReady(int viewId) {
422426
final GoogleMapViewController viewController =
423427
GoogleMapViewController(viewId);
424428
widget.onViewCreated(viewController);

lib/src/google_maps_navigation_view.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,18 @@ class GoogleMapsNavigationViewState
146146
navigationViewOptions: NavigationViewOptions(
147147
navigationUIEnabledPreference:
148148
widget.initialNavigationUIEnabledPreference)),
149-
onMapReady: _onPlatformViewCreated);
149+
onPlatformViewCreated: _onPlatformViewCreated,
150+
onMapReady: _onMapReady);
150151
}
151152

152-
/// Callback method when platform view is created.
153+
/// Callback method for platform view is created event.
153154
void _onPlatformViewCreated(int viewId) {
154155
initMapViewListeners(viewId);
155156
_initNavigationViewListeners(viewId);
157+
}
158+
159+
/// Callback method for map ready event.
160+
void _onMapReady(int viewId) {
156161
final GoogleNavigationViewController viewController =
157162
GoogleNavigationViewController(viewId);
158163
widget.onViewCreated(viewController);

lib/src/google_navigation_flutter_android.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,31 @@ class GoogleMapsNavigationAndroid extends GoogleMapsNavigationPlatform {
5050
@override
5151
Widget buildMapView(
5252
{required MapViewInitializationOptions initializationOptions,
53+
required PlatformViewCreatedCallback onPlatformViewCreated,
5354
required MapReadyCallback onMapReady}) {
5455
return _buildView(
5556
mapViewType: MapViewType.map,
5657
initializationOptions: initializationOptions,
58+
onPlatformViewCreated: onPlatformViewCreated,
5759
onMapReady: onMapReady);
5860
}
5961

6062
@override
6163
Widget buildNavigationView(
6264
{required MapViewInitializationOptions initializationOptions,
65+
required PlatformViewCreatedCallback onPlatformViewCreated,
6366
required MapReadyCallback onMapReady}) {
6467
return _buildView(
6568
mapViewType: MapViewType.navigation,
6669
initializationOptions: initializationOptions,
70+
onPlatformViewCreated: onPlatformViewCreated,
6771
onMapReady: onMapReady);
6872
}
6973

7074
Widget _buildView(
7175
{required MapViewType mapViewType,
7276
required MapViewInitializationOptions initializationOptions,
77+
required PlatformViewCreatedCallback onPlatformViewCreated,
7378
required MapReadyCallback onMapReady}) {
7479
// Initialize method channel for view communication if needed.
7580
viewAPI.ensureViewAPISetUp();
@@ -87,6 +92,8 @@ class GoogleMapsNavigationAndroid extends GoogleMapsNavigationPlatform {
8792
return AndroidView(
8893
viewType: viewType,
8994
onPlatformViewCreated: (int viewId) async {
95+
onPlatformViewCreated(viewId);
96+
9097
// On Android the map is initialized asyncronously.
9198
// Wait map to be ready before calling [onMapReady] callback
9299
await viewAPI.awaitMapReady(viewId: viewId);

0 commit comments

Comments
 (0)