0

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.

enter image description here

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.

enter image description here enter image description here

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.

Wenhui Luo
  • 266
  • 3
  • 13

1 Answers1

1

after some sleep, I feel it can be simply solved by checking the snapshot.data

        return snapshot.hasData
            ? ProviderApp(snapshot.data.latitude)
            : Center(child: CircularProgressIndicator());
Wenhui Luo
  • 266
  • 3
  • 13