Open ItsPierre opened 5 years ago
Please add the output of flutter doctor -v
.
Have you tried with a release build? Debug builds are never representative for measuring performance.
Please add the output of
flutter doctor -v
.
I will add the flutter doctor -v
later
Have you tried with a release build? Debug builds are never representative for measuring performance.
Yes, I did try release builds, but it is still lagging, when initializing
Please add the output of
flutter doctor -v
.
I added the flutter doctor. But I think, this is a general problem.
But I think, this is a general problem.
It's not about possible errors flutter doctor
might report.
flutter doctor -v
output is valuable information about the context where the problem reproduced for you.
Same for me. It takes a while to build my StatelessWidget with google map inside SizedBox 300x300. Without google maps, the widget builds instantly, otherwise the delay for the StatelessWidget to appear is noticeable. This is my output:
[✓] Flutter (Channel stable, v1.2.1, on Mac OS X 10.14.3 18D109, locale pl-PL) • Flutter version 1.2.1 at /Users/mat/dev/flutter • Framework revision 8661d8aecd (5 weeks ago), 2019-02-14 19:19:53 -0800 • Engine revision 3757390fa4 • Dart version 2.1.2 (build 2.1.2-dev.0.0 0a7dcf17eb)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/mat/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-28, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01) • All Android licenses accepted.
[✓] iOS toolchain - develop for iOS devices (Xcode 10.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 10.1, Build version 10B61 • ios-deploy 1.9.4 • CocoaPods version 1.5.3
[✓] Android Studio (version 3.3) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 33.3.1 • Dart plugin version 182.5215 • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
[✓] Connected device (1 available) • Android SDK built for x86 • emulator-5554 • android-x86 • Android 8.1.0 (API 27) (emulator)
• No issues found!
Experiencing the same in my release builds. Quite a bit of jank.
I'm not sure how this one can easily be solved as embedding a native platform view as expensive as a Google Map view isn't going to be easy without hindering Flutter's UI performance.
For now I added a delay in initState to load Google Maps:
Future.delayed(const Duration(milliseconds: 500), () { setState(() { _showGoogleMaps = true; }); });
Using this plugin really degrades the performance of the Widget tree for me... i had to put the map on a separate, isolate screen ;/
@danielcmm How do you put a widget on a separate isolate?
For now I added a delay in initState to load Google Maps:
Future.delayed(const Duration(milliseconds: 500), () { setState(() { _showGoogleMaps = true; }); });
Works nice. Good Workaround utill it is fixed.
It would be good to study a timeline showing what is actually happening. Can someone who is seeing this run a profile build and collect a timeline of the behaviour?
It would also be good to see a short app that reproduces the problem, that would save us some time when we get around to debugging this.
I tried to make a simple app to show the issue:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final controller = PageController();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Expanded(
child: PageView(
controller: controller,
children: [
Container(
decoration: BoxDecoration(
gradient: LinearGradient(stops: [0, 1], colors: [Colors.blue, Colors.transparent]),
),
),
MapPage(),
],
),
),
RaisedButton(
onPressed: () => controller.animateToPage(
controller.page == 0 ? 1 : 0,
duration: Duration(milliseconds: 350),
curve: Curves.linear,
),
child: Text('Switch page'),
)
],
),
),
);
}
}
class MapPage extends StatefulWidget {
@override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> with AutomaticKeepAliveClientMixin {
bool _keepAlive = false;
@override
Widget build(BuildContext context) {
super.build(context);
return SafeArea(
child: ListView(
children: [
Row(
children: [
Checkbox(
value: _keepAlive,
onChanged: (v) {
_keepAlive = v;
updateKeepAlive();
setState(() {});
},
),
Text('Keep alive'),
],
),
SizedBox(
height: 300,
child: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
),
),
),
],
),
);
}
@override
bool get wantKeepAlive => _keepAlive;
}
The app shows a PageView
that can switch to a page with a map. It highlights 3 different cases:
Here's a timeline of the first initialization with lag: timeline_2020_1_18-1579319582040000.json.txt
Please note that it's the first time I check and export a timeline, so let me know if it's not what you expected...
For now I added a delay in initState to load Google Maps: Future.delayed(const Duration(milliseconds: 500), () { setState(() { _showGoogleMaps = true; }); });
Works nice. Good Workaround utill it is fixed.
This didn't help for me, but not sure I'm doing it right.
I have a GoogleMap in a ListView.
If _showGoogleMaps is true, I return the GoogleMap() in the ListView, otherwise I return an empty Container(), when the 500 millisecond timeout is done, the map still lags when initiating.
Does anybody have other solutions? Is there any way to async load the map before it's actually displayed, or maybe load the map before reaching the map in the ListView(), because the moment the ListView() scrolls to the GoogleMap(), the app just freezes until the GoogleMap() is rendered. If the map renders once, scrolling back to it doesn't cause lags.
This can help https://github.com/flutter/plugins/pull/2479
The same issue
Any updates?
For now I added a delay in initState to load Google Maps:
Future.delayed(const Duration(milliseconds: 500), () { setState(() { _showGoogleMaps = true; }); });
Thanks for the suggestion. This is working for now. I used a FutureBuilder
instead, though. For those who are curious:
final Completer<GoogleMapController> _mapController = Completer();
Future _mapFuture = Future.delayed(Duration(milliseconds: 250), () => true);
Widget _buildMap() {
LatLng currentLocation = LocationMonitor.of(context).currentLocation;
return FutureBuilder(
future: _mapFuture,
builder: (context, snapshot) {
if (!snapshot.hasData) {
print("empty");
return Empty();
}
return GoogleMap(
initialCameraPosition: CameraPosition(
target: currentLocation == null ? LatLng(0.0, 0.0) : currentLocation,
zoom: currentLocation == null ? 0 : 15,
),
onMapCreated: (GoogleMapController controller) {
_mapController.complete(controller);
},
myLocationButtonEnabled: false,
myLocationEnabled: true,
);
},
);
}
FutureBuilder
looks like a reasonable work-around, given the time it takes the map view under the plugin to initialize. I'm going to move this out to Stretch Goals at this point, as we don't currently have resources to work on optimizations here.
@cohenadair So basically with the Future builder you are postponing the map draw until the Navigator animation is completed?
@cohenadair So basically with the Future builder you are postponing the map draw until the Navigator animation is completed?
@codepushr That's the idea. Technically, it's not waiting for the Navigator to finish, it's just delaying the map draw 250 ms. As long as the delay is longer than the Navigator animation, everything should be fine.
You may be able to listen for the Navigator animation to finish, so the delay becomes irrelevant, but I didn't look into it, and the 250 ms delay works fine for what I'm trying to do.
But even when the map is initialized, I still have a lot of lag when moving through the map. This experience is fine in native google maps app on any device, but even if I try to release build my app from flutter, any android device is showing a lot of lag. Not an issue on IOS though.
@cohenadair So basically with the Future builder you are postponing the map draw until the Navigator animation is completed?
@codepushr That's the idea. Technically, it's not waiting for the Navigator to finish, it's just delaying the map draw 250 ms. As long as the delay is longer than the Navigator animation, everything should be fine.
You may be able to listen for the Navigator animation to finish, so the delay becomes irrelevant, but I didn't look into it, and the 250 ms delay works fine for what I'm trying to do.
yes exactly it would be nice to able to handle route navigation finish like initState methods for example onRoutingFinished and after that initliazing google maps
hope this also helps:
bool showMap = false;
void initState() {
super.initState();
Future.delayed(const Duration(milliseconds: 250), () {
setState(() {
showMap= true;
});
});
}
and in the build use :
Stack(
children:[
if (showMap) GoogleMap,
Cover,
]
)
where GoogleMap is the GoogleMap Widget and Cover is something like this :
IgnorePointer(
child: AnimatedOpacity(
curve: Curves.easeInCirc,
duration: Duration(milliseconds: 1000),
opacity: showMap ? 0 : 1,
child: Container(
color: Colors.blue,
child: Center(
child: Icon(
FontAwesomeIcons.spinner,
size: 60,
color: Colors.white.withAlpha(100),
),
),
),
),
),
this will add about 250ms before google map start initializing (this will smooth the navigator animation as many suggested) then it adds a one second transition to smooth the appearance of the map it worked well for my use case
I think more clean solution is not to w8 random 250ms but to resolve future at the post frame callback.
Smth like this:
class GodState extends State<God> {
Completer<void> _initCompleter = Completer();
@override
onInitState() {
WidgetsBinding.instance
.addPostFrameCallback((_) => _initCompleter.complete());
}
FutureBuilder(
future: _initCompleter.future,
builder: (...) => ...
);
}
I think more clean solution is not to w8 random 250ms but to resolve future at the post frame callback.
Smth like this:
class GodState extends State<God> { Completer<void> _initCompleter = Completer(); @override onInitState() { WidgetsBinding.instance .addPostFrameCallback((_) => _initCompleter.complete()); } FutureBuilder( future: _initCompleter.future, builder: (...) => ... ); }
Hi @0ttik,
Can you explain how this works a little more? The documentation states that
This callback is run during a frame, just after the persistent frame callbacks (which is when the main rendering pipeline has been flushed)
Does the latter part mean once all animation frames are finished? You wouldn't want the callback invoked part way through the navigation animation.
Hi, @cohenadair!
You are right, in case of navigation animation it won't work. Although you can track it as well using [ModalRoute]
(obtaining it with ModalRoute.of(context)
) and then subscribing to animation state like this:
var modal = ModalRoute.of(context);
modal.animation.addStatusListener(/*dont forget to unsubscribe in this callback*/);
And you just trigger map loading after this callback fires with value you need.
Docs:
P.S. I found lots of ways to better control application flow connected with navigation when I've actually read [ModalRoute] class docs >_<
Finding the Google map too laggy to be useful in a list-view, will need to move it to a separate view for now. Above delays not working for me personally.
@mellowcello77, did You tried lite mode
for a list-view usage?
@niktob560 I looked into it at the time, I think it was for Android only. I ended up using mapbox.
@niktob560 I tried lite mode, but this did not solve the problem.
At the moment, the best workaround seems to be a FutureBuilder, that waits the 200 ms the page transition animation requires. At this time I just show a shimmer-loading effect. After this I initialize the GoogleMap.
Not perfect, but much better, than a lagging animation.
Verified this using a sample app on master version in debug mode and noticed the lag when map tries to open / initialize after directing through a route, as below:
Any updates?
still seeing long wait times for google maps to load
Still there are no changes.
still facing the issue..
Using this plugin really degrades the performance of the Widget tree for me... i had to put the map on a separate, isolate screen ;/
Please @danielcmm, could you share the code to generate an isolate screen?
Any news about this ?
any updates ?
I also have issues with Google map inside ListView, it's lagging always when I try to scroll, not just when initialising.
I also have issues with Google map inside ListView, it's lagging always when I try to scroll, not just when initialising.
@aleksandar-radivojevic Same here. Do you have any luck with this issue ?
Perhaps a new issue should be opened for the ListView problem?
Open new issue for scroll lags #135026
I am just building the Google-Maps widget in my Stateful Widget. This will be opened with the Navigator via a Button click. But as soon, as I click, the app is lagging, while initializing the map. When removing the widget, everything is fine.
I tried to set a
CircularProgressIndicator
and then, setting the map-widget async, but running into the same problem, as soon, as it gets build. I also downloaded and ran the example app from the google-maps-package with the same lagging.How should the map be initilized, that it is first loaded and then set without lagging?
Flutter Doctor
I am developing with Android Studio