I'm having trouble dealing with async
data (namely user GPS coordination) input.
I simplified my app to a calculator app below, which manages the state (a double) by provider
.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(ProviderApp());
class ProviderApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<MyProvider>(
create: (_) => MyProvider(1.55),
child: CalApp(),
);
}
}
class CalApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final myProvider = Provider.of<MyProvider>(context);
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(myProvider.getMyProvider().toString()),
RaisedButton(
child: Text('increase 10%'),
onPressed: () {
myProvider.userProvider();
},
)
],
),
),
),
);
}
}
class MyProvider with ChangeNotifier {
double _myProvider;
MyProvider(this._myProvider);
double getMyProvider() => _myProvider;
void userProvider() {
_myProvider *= 1.1;
notifyListeners();
}
}
now instead of using the initial double
1.55, I'd like to use the user's current latitude as a one-time input by Geolocator
.
1) my 1st solution is passing the latitude down to ProviderApp
via a FutureBuilder
.
this is kinda working but before getting the final page there's an error page saying the FutureBuilder
is passing null
.
If I give the FutureBuilder a initialData: Position(latitude: 20.0),
then the provider will just take that 20.0 and ignore the following latitude data.
import 'dart:ffi';
import 'dart:async';
import 'package:geolocator/geolocator.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(TreeTop());
class TreeTop extends StatelessWidget {
@override
Widget build(BuildContext context) {
Gps gps = Gps();
return FutureBuilder(
future: gps.currentPosition,
// initialData: Position(latitude: 20.0),
builder: (context, snapshot) {
return ProviderApp(snapshot.data.latitude);
},
);
}
}
class ProviderApp extends StatelessWidget {
final double myNum;
ProviderApp(this.myNum);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<MyProvider>(
create: (_) => MyProvider(myNum),
child: CalApp(),
);
}
}
class CalApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final myProvider = Provider.of<MyProvider>(context);
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(myProvider.getMyProvider().toString()),
RaisedButton(
child: Text('increase 10%'),
onPressed: () {
myProvider.userProvider();
},
)
],
),
),
),
);
}
}
class MyProvider with ChangeNotifier {
double _myProvider;
MyProvider(this._myProvider);
double getMyProvider() => _myProvider;
void userProvider() {
_myProvider *= 1.1;
notifyListeners();
}
}
class Gps {
//
// get * one-time * user coordination via geolocator
//
Future<Position> currentPosition = Geolocator().getCurrentPosition(
desiredAccuracy: LocationAccuracy.bestForNavigation,
locationPermissionLevel: GeolocationPermission.locationWhenInUse);
}
2) then looing at Rémi Rousselet's solution at from Setting provider value in FutureBuilder,
I tried to modify MyProvider
constructor but failed because I can't make the constructor async.
3) now I'm thinking to make maybe a FutureProvider
to inject into the ChangeNotifierProvider
but I really doubt.
At this point, I feel I'm fighting with the framework and packages rather than letting them help me, so I hope maybe you can give me some advice.