从FutureBuilder传递异步数据(GPS协调)到提供程序/设置异步构造函数

时间:2020-01-04 08:10:24

标签: asynchronous flutter dart flutter-provider

我在处理async数据(即用户GPS协调)输入时遇到问题。

我将我的应用简化为下面的计算器应用,该应用通过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();
  }
}

现在,我不想使用初始的double 1.55,而是想将用户当前的纬度用作Geolocator的一次性输入。

1)我的第一个解决方案是将纬度通过ProviderApp传递到FutureBuilder

这有点奏效,但是在获得最终页面之前,有一个错误页面,指出FutureBuilder正在传递null

如果我给FutureBuilder一个initialData: Position(latitude: 20.0),,那么提供商将只收取20.0并忽略以下纬度数据。

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),然后在from Setting provider value in FutureBuilder寻求RémiRousselet的解决方案, 我试图修改MyProvider构造函数,但由于无法使构造函数异步而失败。

3)现在我正在考虑制作一个FutureProvider注入ChangeNotifierProvider中,但我真的对此表示怀疑。

在这一点上,我觉得我正在与框架和软件包进行斗争,而不是让它们来帮助我,所以我希望也许您能给我一些建议。

1 个答案:

答案 0 :(得分:0)

睡一觉后,我觉得可以简单地通过检查快照来解决此问题。

        return snapshot.hasData
            ? ProviderApp(snapshot.data.latitude)
            : Center(child: CircularProgressIndicator());