Thanks to visit codestin.com
Credit goes to github.com

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

[google_maps_flutter] Clean up google_maps_flutter plugin #3206

Merged
merged 15 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 1.0.4

* Cleanup of Android code:
* A few minor formatting changes and additions of `@Nullable` annotations.
* Removed pass-through of `activityHashCode` to `GoogleMapController`.
* Replaced custom lifecycle state ints with `androidx.lifecycle.Lifecycle.State` enum.
* Fixed a bug where the Lifecycle object was being leaked `onDetachFromActivity`, by nulling out the field.
* Moved GoogleMapListener to its own file. Declaring multiple top level classes in the same file is discouraged.

## 1.0.3

* Update android compileSdkVersion to 29.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.android.tools.build:gradle:3.5.0'
}
}

Expand All @@ -33,6 +33,7 @@ android {
}

dependencies {
implementation "androidx.annotation:annotation:1.1.0"
implementation 'com.google.android.gms:play-services-maps:17.0.0'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import android.app.Application;
import android.content.Context;
import android.graphics.Rect;
import androidx.annotation.Nullable;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add androidx.annotation to the plugin's build.gradle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Various classes in the plugin already depend on this annotation or the NonNull equivalent, so it appears not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably wrong that we didn't have it so far, I think these get brought in by the Android embedding right now, though for consistency with other dependencies and for future compatibility (in the very unlikely event that the embedding is going to drop the dependency) I'd be explicit about the dependencies.

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Lifecycle.State;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLngBounds;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry;
import java.util.concurrent.atomic.AtomicInteger;

class GoogleMapBuilder implements GoogleMapOptionsSink {
private final GoogleMapOptions options = new GoogleMapOptions();
Expand All @@ -32,24 +33,15 @@ class GoogleMapBuilder implements GoogleMapOptionsSink {
GoogleMapController build(
int id,
Context context,
AtomicInteger state,
State lifecycleState,
BinaryMessenger binaryMessenger,
Application application,
Lifecycle lifecycle,
PluginRegistry.Registrar registrar,
int activityHashCode) {
@Nullable Application application,
@Nullable Lifecycle lifecycle,
@Nullable PluginRegistry.Registrar registrar) {
final GoogleMapController controller =
new GoogleMapController(
id,
context,
state,
binaryMessenger,
application,
lifecycle,
registrar,
activityHashCode,
options);
controller.init();
id, context, binaryMessenger, application, lifecycle, registrar, options);
controller.init(lifecycleState);
controller.setMyLocationEnabled(myLocationEnabled);
controller.setMyLocationButtonEnabled(myLocationButtonEnabled);
controller.setIndoorEnabled(indoorEnabled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@

package io.flutter.plugins.googlemaps;

import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.CREATED;
import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.DESTROYED;
import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.PAUSED;
import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.RESUMED;
import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.STARTED;
import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.STOPPED;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
Expand All @@ -26,6 +19,7 @@
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Lifecycle.State;
import androidx.lifecycle.LifecycleOwner;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.GoogleMap;
Expand Down Expand Up @@ -53,7 +47,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/** Controller of a single GoogleMaps MapView instance. */
final class GoogleMapController
Expand All @@ -68,7 +61,6 @@ final class GoogleMapController

private static final String TAG = "GoogleMapController";
private final int id;
private final AtomicInteger activityState;
private final MethodChannel methodChannel;
private final GoogleMapOptions options;
@Nullable private MapView mapView;
Expand All @@ -83,13 +75,12 @@ final class GoogleMapController
private boolean disposed = false;
private final float density;
private MethodChannel.Result mapReadyResult;
private final int
activityHashCode; // Do not use directly, use getActivityHashCode() instead to get correct hashCode for both v1 and v2 embedding.
private final Lifecycle lifecycle;
@Nullable private final Lifecycle lifecycle;
private final Context context;
private final Application
mApplication; // Do not use direclty, use getApplication() instead to get correct application object for both v1 and v2 embedding.
private final PluginRegistry.Registrar registrar; // For v1 embedding only.
// Do not use directly, use getApplication() instead to get correct application object for both v1
// and v2 embedding.
@Nullable private final Application mApplication;
@Nullable private final PluginRegistry.Registrar registrar; // For v1 embedding only.
private final MarkersController markersController;
private final PolygonsController polygonsController;
private final PolylinesController polylinesController;
Expand All @@ -102,16 +93,13 @@ final class GoogleMapController
GoogleMapController(
int id,
Context context,
AtomicInteger activityState,
BinaryMessenger binaryMessenger,
Application application,
Lifecycle lifecycle,
PluginRegistry.Registrar registrar,
int registrarActivityHashCode,
@Nullable Application application,
@Nullable Lifecycle lifecycle,
@Nullable PluginRegistry.Registrar registrar,
GoogleMapOptions options) {
this.id = id;
this.context = context;
this.activityState = activityState;
this.options = options;
this.mapView = new MapView(context, options);
this.density = context.getResources().getDisplayMetrics().density;
Expand All @@ -120,7 +108,6 @@ final class GoogleMapController
mApplication = application;
this.lifecycle = lifecycle;
this.registrar = registrar;
this.activityHashCode = registrarActivityHashCode;
this.markersController = new MarkersController(methodChannel);
this.polygonsController = new PolygonsController(methodChannel, density);
this.polylinesController = new PolylinesController(methodChannel, density);
Expand All @@ -132,21 +119,8 @@ public View getView() {
return mapView;
}

void init() {
switch (activityState.get()) {
case STOPPED:
mapView.onCreate(null);
mapView.onStart();
mapView.onResume();
mapView.onPause();
mapView.onStop();
break;
case PAUSED:
mapView.onCreate(null);
mapView.onStart();
mapView.onResume();
mapView.onPause();
break;
void init(State lifecycleState) {
switch (lifecycleState) {
case RESUMED:
mapView.onCreate(null);
mapView.onStart();
Expand All @@ -160,11 +134,9 @@ void init() {
mapView.onCreate(null);
break;
case DESTROYED:
// Nothing to do, the activity has been completely destroyed.
case INITIALIZED:
// Nothing to do, the activity has been completely destroyed or not yet created.
break;
default:
throw new IllegalArgumentException(
"Cannot interpret " + activityState.get() + " as an activity state");
}
if (lifecycle != null) {
lifecycle.addObserver(this);
Expand Down Expand Up @@ -556,14 +528,14 @@ private void setGoogleMapListener(@Nullable GoogleMapListener listener) {
// does. This will override it when available even with the annotation commented out.
public void onInputConnectionLocked() {
// TODO(mklim): Remove this empty override once https://github.com/flutter/flutter/issues/40126 is fixed in stable.
};
}

// @Override
// The minimum supported version of Flutter doesn't have this method on the PlatformView interface, but the maximum
// does. This will override it when available even with the annotation commented out.
public void onInputConnectionUnlocked() {
// TODO(mklim): Remove this empty override once https://github.com/flutter/flutter/issues/40126 is fixed in stable.
};
}

// Application.ActivityLifecycleCallbacks methods
@Override
Expand Down Expand Up @@ -880,7 +852,9 @@ private int getActivityHashCode() {
if (registrar != null && registrar.activity() != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmmm staring at this snippet a little more I'm worried this may crash with the old embedding when the activity is in the background and some lifecycle event for the same application happens.
We used to cache the activityHashCode, and we stopped caching at #2488 cc @cyanglaz do you remember the context for this change? was it safe to stop caching the activity hashCode in that PR?

return registrar.activity().hashCode();
} else {
return activityHashCode;
// TODO(cyanglaz): Remove `getActivityHashCode()` and use a cached hashCode when creating the view for V1 embedding.
// https://github.com/flutter/flutter/issues/69128
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a comment here explaining that registrar is null for the v2 embedding where the activityHashCode shouldn't be used. If we're certain this isn't being I think we better throw - we better get a clear crash than some strange value that may lead to easy to understand bugs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it's worth noting that this could be considered a breaking change.

}
}

Expand Down Expand Up @@ -916,16 +890,3 @@ public void setBuildingsEnabled(boolean buildingsEnabled) {
this.buildingsEnabled = buildingsEnabled;
}
}

interface GoogleMapListener
extends GoogleMap.OnCameraIdleListener,
GoogleMap.OnCameraMoveListener,
GoogleMap.OnCameraMoveStartedListener,
GoogleMap.OnInfoWindowClickListener,
GoogleMap.OnMarkerClickListener,
GoogleMap.OnPolygonClickListener,
GoogleMap.OnPolylineClickListener,
GoogleMap.OnCircleClickListener,
GoogleMap.OnMapClickListener,
GoogleMap.OnMapLongClickListener,
GoogleMap.OnMarkerDragListener {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,36 @@

import android.app.Application;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Lifecycle.State;
import com.google.android.gms.maps.model.CameraPosition;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class GoogleMapFactory extends PlatformViewFactory {

private final AtomicInteger mActivityState;
private final AtomicReference<State> lifecycleState;
private final BinaryMessenger binaryMessenger;
private final Application application;
private final int activityHashCode;
private final Lifecycle lifecycle;
private final PluginRegistry.Registrar registrar; // V1 embedding only.
@Nullable private final Application application;
@Nullable private final Lifecycle lifecycle;
@Nullable private final PluginRegistry.Registrar registrar; // V1 embedding only.

GoogleMapFactory(
AtomicInteger state,
AtomicReference<State> lifecycleState,
BinaryMessenger binaryMessenger,
Application application,
Lifecycle lifecycle,
PluginRegistry.Registrar registrar,
int activityHashCode) {
@Nullable Application application,
@Nullable Lifecycle lifecycle,
@Nullable PluginRegistry.Registrar registrar) {
super(StandardMessageCodec.INSTANCE);
mActivityState = state;
this.lifecycleState = lifecycleState;
this.binaryMessenger = binaryMessenger;
this.application = application;
this.activityHashCode = activityHashCode;
this.lifecycle = lifecycle;
this.registrar = registrar;
}
Expand Down Expand Up @@ -65,13 +64,6 @@ public PlatformView create(Context context, int id, Object args) {
builder.setInitialCircles(params.get("circlesToAdd"));
}
return builder.build(
id,
context,
mActivityState,
binaryMessenger,
application,
lifecycle,
registrar,
activityHashCode);
id, context, lifecycleState.get(), binaryMessenger, application, lifecycle, registrar);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.googlemaps;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the license header (you can copy from any other file)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks


import com.google.android.gms.maps.GoogleMap;

interface GoogleMapListener
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with moving this here if that's how you prefer it, curious though - is there a reference to a style guide / best practices doc with the determination that multiple top level classes is bad?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find any formal documentation, but it can cause compiler problems. See discussion in https://stackoverflow.com/q/2336692 for example.

extends GoogleMap.OnCameraIdleListener,
GoogleMap.OnCameraMoveListener,
GoogleMap.OnCameraMoveStartedListener,
GoogleMap.OnInfoWindowClickListener,
GoogleMap.OnMarkerClickListener,
GoogleMap.OnPolygonClickListener,
GoogleMap.OnPolylineClickListener,
GoogleMap.OnCircleClickListener,
GoogleMap.OnMapClickListener,
GoogleMap.OnMapLongClickListener,
GoogleMap.OnMarkerDragListener {}
Loading