Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 8a613b9

Browse files
authored
[google_maps_flutter] Overhaul lifecycle management in GoogleMapsPlugin (#3213)
GoogleMapController is now uniformly driven by implementing DefaultLifecycleObserver. That observer is registered to a lifecycle passed via the new LifecycleProvider interface, which has 3 implementations: 1. For v2 plugin registration, GoogleMapsPlugin implements the interface and holds the lifecycle in a field, which is itself controlled by ActivityAware methods. 2. For v1 plugin registration, if the activity implements LifecycleOwner, it's lifecycle is used directly. 3. For v1 plugin registration, if the activity does not implement LifecycleOwner, a proxy lifecycle is created via ActivityLifecycleCallbacks.
1 parent d3bbef8 commit 8a613b9

File tree

8 files changed

+158
-283
lines changed

8 files changed

+158
-283
lines changed

packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 1.0.5
2+
3+
Overhaul lifecycle management in GoogleMapsPlugin.
4+
5+
GoogleMapController is now uniformly driven by implementing `DefaultLifecycleObserver`. That observer is registered to a lifecycle from one of three sources:
6+
7+
1. For v2 plugin registration, `GoogleMapsPlugin` obtains the lifecycle via `ActivityAware` methods.
8+
2. For v1 plugin registration, if the activity implements `LifecycleOwner`, it's lifecycle is used directly.
9+
3. For v1 plugin registration, if the activity does not implement `LifecycleOwner`, a proxy lifecycle is created and driven via `ActivityLifecycleCallbacks`.
10+
111
## 1.0.4
212

313
* Cleanup of Android code:

packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,12 @@
44

55
package io.flutter.plugins.googlemaps;
66

7-
import android.app.Application;
87
import android.content.Context;
98
import android.graphics.Rect;
10-
import androidx.annotation.Nullable;
11-
import androidx.lifecycle.Lifecycle;
12-
import androidx.lifecycle.Lifecycle.State;
139
import com.google.android.gms.maps.GoogleMapOptions;
1410
import com.google.android.gms.maps.model.CameraPosition;
1511
import com.google.android.gms.maps.model.LatLngBounds;
1612
import io.flutter.plugin.common.BinaryMessenger;
17-
import io.flutter.plugin.common.PluginRegistry;
1813

1914
class GoogleMapBuilder implements GoogleMapOptionsSink {
2015
private final GoogleMapOptions options = new GoogleMapOptions();
@@ -33,15 +28,11 @@ class GoogleMapBuilder implements GoogleMapOptionsSink {
3328
GoogleMapController build(
3429
int id,
3530
Context context,
36-
State lifecycleState,
3731
BinaryMessenger binaryMessenger,
38-
@Nullable Application application,
39-
@Nullable Lifecycle lifecycle,
40-
@Nullable PluginRegistry.Registrar registrar) {
32+
LifecycleProvider lifecycleProvider) {
4133
final GoogleMapController controller =
42-
new GoogleMapController(
43-
id, context, binaryMessenger, application, lifecycle, registrar, options);
44-
controller.init(lifecycleState);
34+
new GoogleMapController(id, context, binaryMessenger, lifecycleProvider, options);
35+
controller.init();
4536
controller.setMyLocationEnabled(myLocationEnabled);
4637
controller.setMyLocationButtonEnabled(myLocationButtonEnabled);
4738
controller.setIndoorEnabled(indoorEnabled);

packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java

Lines changed: 12 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
import android.Manifest;
88
import android.annotation.SuppressLint;
9-
import android.app.Activity;
10-
import android.app.Application;
119
import android.content.Context;
1210
import android.content.pm.PackageManager;
1311
import android.graphics.Bitmap;
@@ -19,7 +17,6 @@
1917
import androidx.annotation.Nullable;
2018
import androidx.lifecycle.DefaultLifecycleObserver;
2119
import androidx.lifecycle.Lifecycle;
22-
import androidx.lifecycle.Lifecycle.State;
2320
import androidx.lifecycle.LifecycleOwner;
2421
import com.google.android.gms.maps.CameraUpdate;
2522
import com.google.android.gms.maps.GoogleMap;
@@ -39,7 +36,6 @@
3936
import io.flutter.plugin.common.BinaryMessenger;
4037
import io.flutter.plugin.common.MethodCall;
4138
import io.flutter.plugin.common.MethodChannel;
42-
import io.flutter.plugin.common.PluginRegistry;
4339
import io.flutter.plugin.platform.PlatformView;
4440
import java.io.ByteArrayOutputStream;
4541
import java.util.ArrayList;
@@ -50,8 +46,7 @@
5046

5147
/** Controller of a single GoogleMaps MapView instance. */
5248
final class GoogleMapController
53-
implements Application.ActivityLifecycleCallbacks,
54-
DefaultLifecycleObserver,
49+
implements DefaultLifecycleObserver,
5550
ActivityPluginBinding.OnSaveInstanceStateListener,
5651
GoogleMapOptionsSink,
5752
MethodChannel.MethodCallHandler,
@@ -75,12 +70,8 @@ final class GoogleMapController
7570
private boolean disposed = false;
7671
private final float density;
7772
private MethodChannel.Result mapReadyResult;
78-
@Nullable private final Lifecycle lifecycle;
7973
private final Context context;
80-
// Do not use directly, use getApplication() instead to get correct application object for both v1
81-
// and v2 embedding.
82-
@Nullable private final Application mApplication;
83-
@Nullable private final PluginRegistry.Registrar registrar; // For v1 embedding only.
74+
private final LifecycleProvider lifecycleProvider;
8475
private final MarkersController markersController;
8576
private final PolygonsController polygonsController;
8677
private final PolylinesController polylinesController;
@@ -94,9 +85,7 @@ final class GoogleMapController
9485
int id,
9586
Context context,
9687
BinaryMessenger binaryMessenger,
97-
@Nullable Application application,
98-
@Nullable Lifecycle lifecycle,
99-
@Nullable PluginRegistry.Registrar registrar,
88+
LifecycleProvider lifecycleProvider,
10089
GoogleMapOptions options) {
10190
this.id = id;
10291
this.context = context;
@@ -105,9 +94,7 @@ final class GoogleMapController
10594
this.density = context.getResources().getDisplayMetrics().density;
10695
methodChannel = new MethodChannel(binaryMessenger, "plugins.flutter.io/google_maps_" + id);
10796
methodChannel.setMethodCallHandler(this);
108-
mApplication = application;
109-
this.lifecycle = lifecycle;
110-
this.registrar = registrar;
97+
this.lifecycleProvider = lifecycleProvider;
11198
this.markersController = new MarkersController(methodChannel);
11299
this.polygonsController = new PolygonsController(methodChannel, density);
113100
this.polylinesController = new PolylinesController(methodChannel, density);
@@ -119,30 +106,8 @@ public View getView() {
119106
return mapView;
120107
}
121108

122-
void init(State lifecycleState) {
123-
switch (lifecycleState) {
124-
case RESUMED:
125-
mapView.onCreate(null);
126-
mapView.onStart();
127-
mapView.onResume();
128-
break;
129-
case STARTED:
130-
mapView.onCreate(null);
131-
mapView.onStart();
132-
break;
133-
case CREATED:
134-
mapView.onCreate(null);
135-
break;
136-
case DESTROYED:
137-
case INITIALIZED:
138-
// Nothing to do, the activity has been completely destroyed or not yet created.
139-
break;
140-
}
141-
if (lifecycle != null) {
142-
lifecycle.addObserver(this);
143-
} else {
144-
getApplication().registerActivityLifecycleCallbacks(this);
145-
}
109+
void init() {
110+
lifecycleProvider.getLifecycle().addObserver(this);
146111
mapView.getMapAsync(this);
147112
}
148113

@@ -507,7 +472,10 @@ public void dispose() {
507472
methodChannel.setMethodCallHandler(null);
508473
setGoogleMapListener(null);
509474
destroyMapViewIfNecessary();
510-
getApplication().unregisterActivityLifecycleCallbacks(this);
475+
Lifecycle lifecycle = lifecycleProvider.getLifecycle();
476+
if (lifecycle != null) {
477+
lifecycle.removeObserver(this);
478+
}
511479
}
512480

513481
private void setGoogleMapListener(@Nullable GoogleMapListener listener) {
@@ -537,64 +505,7 @@ public void onInputConnectionUnlocked() {
537505
// TODO(mklim): Remove this empty override once https://github.com/flutter/flutter/issues/40126 is fixed in stable.
538506
}
539507

540-
// Application.ActivityLifecycleCallbacks methods
541-
@Override
542-
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
543-
if (disposed || activity.hashCode() != getActivityHashCode()) {
544-
return;
545-
}
546-
mapView.onCreate(savedInstanceState);
547-
}
548-
549-
@Override
550-
public void onActivityStarted(Activity activity) {
551-
if (disposed || activity.hashCode() != getActivityHashCode()) {
552-
return;
553-
}
554-
mapView.onStart();
555-
}
556-
557-
@Override
558-
public void onActivityResumed(Activity activity) {
559-
if (disposed || activity.hashCode() != getActivityHashCode()) {
560-
return;
561-
}
562-
mapView.onResume();
563-
}
564-
565-
@Override
566-
public void onActivityPaused(Activity activity) {
567-
if (disposed || activity.hashCode() != getActivityHashCode()) {
568-
return;
569-
}
570-
mapView.onPause();
571-
}
572-
573-
@Override
574-
public void onActivityStopped(Activity activity) {
575-
if (disposed || activity.hashCode() != getActivityHashCode()) {
576-
return;
577-
}
578-
mapView.onStop();
579-
}
580-
581-
@Override
582-
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
583-
if (disposed || activity.hashCode() != getActivityHashCode()) {
584-
return;
585-
}
586-
mapView.onSaveInstanceState(outState);
587-
}
588-
589-
@Override
590-
public void onActivityDestroyed(Activity activity) {
591-
if (disposed || activity.hashCode() != getActivityHashCode()) {
592-
return;
593-
}
594-
destroyMapViewIfNecessary();
595-
}
596-
597-
// DefaultLifecycleObserver and OnSaveInstanceStateListener
508+
// DefaultLifecycleObserver
598509

599510
@Override
600511
public void onCreate(@NonNull LifecycleOwner owner) {
@@ -638,6 +549,7 @@ public void onStop(@NonNull LifecycleOwner owner) {
638549

639550
@Override
640551
public void onDestroy(@NonNull LifecycleOwner owner) {
552+
owner.getLifecycle().removeObserver(this);
641553
if (disposed) {
642554
return;
643555
}
@@ -848,24 +760,6 @@ private int checkSelfPermission(String permission) {
848760
permission, android.os.Process.myPid(), android.os.Process.myUid());
849761
}
850762

851-
private int getActivityHashCode() {
852-
if (registrar != null && registrar.activity() != null) {
853-
return registrar.activity().hashCode();
854-
} else {
855-
// TODO(cyanglaz): Remove `getActivityHashCode()` and use a cached hashCode when creating the view for V1 embedding.
856-
// https://github.com/flutter/flutter/issues/69128
857-
return -1;
858-
}
859-
}
860-
861-
private Application getApplication() {
862-
if (registrar != null && registrar.activity() != null) {
863-
return registrar.activity().getApplication();
864-
} else {
865-
return mApplication;
866-
}
867-
}
868-
869763
private void destroyMapViewIfNecessary() {
870764
if (mapView == null) {
871765
return;

packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,23 @@
44

55
package io.flutter.plugins.googlemaps;
66

7-
import android.app.Application;
87
import android.content.Context;
9-
import androidx.annotation.Nullable;
10-
import androidx.lifecycle.Lifecycle;
11-
import androidx.lifecycle.Lifecycle.State;
128
import com.google.android.gms.maps.model.CameraPosition;
139
import io.flutter.plugin.common.BinaryMessenger;
14-
import io.flutter.plugin.common.PluginRegistry;
1510
import io.flutter.plugin.common.StandardMessageCodec;
1611
import io.flutter.plugin.platform.PlatformView;
1712
import io.flutter.plugin.platform.PlatformViewFactory;
1813
import java.util.Map;
19-
import java.util.concurrent.atomic.AtomicReference;
2014

2115
public class GoogleMapFactory extends PlatformViewFactory {
2216

23-
private final AtomicReference<State> lifecycleState;
2417
private final BinaryMessenger binaryMessenger;
25-
@Nullable private final Application application;
26-
@Nullable private final Lifecycle lifecycle;
27-
@Nullable private final PluginRegistry.Registrar registrar; // V1 embedding only.
18+
private final LifecycleProvider lifecycleProvider;
2819

29-
GoogleMapFactory(
30-
AtomicReference<State> lifecycleState,
31-
BinaryMessenger binaryMessenger,
32-
@Nullable Application application,
33-
@Nullable Lifecycle lifecycle,
34-
@Nullable PluginRegistry.Registrar registrar) {
20+
GoogleMapFactory(BinaryMessenger binaryMessenger, LifecycleProvider lifecycleProvider) {
3521
super(StandardMessageCodec.INSTANCE);
36-
this.lifecycleState = lifecycleState;
3722
this.binaryMessenger = binaryMessenger;
38-
this.application = application;
39-
this.lifecycle = lifecycle;
40-
this.registrar = registrar;
23+
this.lifecycleProvider = lifecycleProvider;
4124
}
4225

4326
@SuppressWarnings("unchecked")
@@ -63,7 +46,6 @@ public PlatformView create(Context context, int id, Object args) {
6346
if (params.containsKey("circlesToAdd")) {
6447
builder.setInitialCircles(params.get("circlesToAdd"));
6548
}
66-
return builder.build(
67-
id, context, lifecycleState.get(), binaryMessenger, application, lifecycle, registrar);
49+
return builder.build(id, context, binaryMessenger, lifecycleProvider);
6850
}
6951
}

0 commit comments

Comments
 (0)