【问题标题】:Flutter FutureBuilder, Future.wait with Geolocator Future and another future not fetching dataFlutter FutureBuilder,Future.wait 与 Geolocator Future 和另一个未获取数据的未来
【发布时间】:2021-02-14 05:43:21
【问题描述】:

自从我开始为这个问题苦苦挣扎已经一周了,所以我完全不知所措。 在我的代码中 - 请参见下文 - 我需要解析两个期货来构建页面。一个 - 从 Geolocator 包获取地图的用户位置,另一个是该位置用户可用的工作/活动列表。活动/工作未来也依赖于获取用户的位置,然后获取数据表单 API。

我面临的问题并尝试了几种方法(Location 和 Geolocator 包),但我得到的问题是 futureSnapshot 连接完成(转到“完成”)但未来的位置部分为空。 即使我根据 Pieter 的建议创建了一个 Future 方法,我仍然得到

“W/Geolocator(12158):位置权限不是权限的一部分 发送到 onRequestPermissionsResult 方法。 W/IInputConnectionWrapper(12158):reportFullscreenMode 不存在 输入连接"

创建的 Future 现在被 fetchJobsFuture 使用并提供给 MapCard 小部件

import 'package:geolocator/geolocator.dart';

Future<Position> getUserPosition() async {
  var _permissionGranted = await Geolocator.checkPermission();

  if (_permissionGranted != LocationPermission.always ||
      _permissionGranted != LocationPermission.whileInUse) {
    await Geolocator.requestPermission();
  }

  final position = await Geolocator.getCurrentPosition();
  return position;
}

这是页面的全部代码:

class HomePage extends StatefulWidget {
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      static const double _desiredSplit =
          0.6; // ONLY one after the decimal point!!!
      double currentSplit = _desiredSplit;
      static const double _minMapFragment = 0.04;
      double listTopBarHeight = 42.0;
    
      Future<JobList> fetchJobsFuture;
      JobList currentListOfJobs;
    
      Future<Position> userPositionFuture;
      Position userPosition;
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        currentListOfJobs = Provider.of<JobList>(context, listen: false);
    
        getUserPosition().then((value) => userPosition = value).then((_) {
          fetchJobsFuture = currentListOfJobs.getCurrentJobList();
        });
    
        return Scaffold(
          backgroundColor: Colors.white,
          body: FutureBuilder(
              future: fetchJobsFuture,
              builder: (context, AsyncSnapshot<JobList> futureSnaphot) {
                if (!futureSnaphot.hasData) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                } else {
                  return Column(
                    mainAxisSize: MainAxisSize.max,
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      SizedBox(
                        height: 200,
                        child: Container(
                          child: MapCard(
                            latitude: userPosition.latitude,
                            longitude: userPosition.longitude,
                          ),
                        ),
                      ),
                      SizedBox(
                        height: 300,
                        child: ListCard(
                          jobList: futureSnaphot.data,
                        ),
                      ),
                    ],
                  );
                }
              }),
        );
      }
    }

任何想法或建议将不胜感激 - 谢谢!干杯!

【问题讨论】:

    标签: flutter geolocation


    【解决方案1】:

    我对问题进行了深入研究,最后询问了开发 Geolocator 软件包的人可能导致以下问题的原因:

    W/Activity(24892): Can reqeust only one set of permissions at a time
    W/Geolocator(24892): Location permissions not part of permissions send to onRequestPermissionsResult method.
    

    如果您对这些想法感兴趣 - 这是完整的主题:https://github.com/Baseflow/flutter-geolocator/issues/661

    为了简短。如果遇到类似问题:

    1. 请注意,构建器会快速多次调用期货 继承(每次重建),以便与 Geolocator 的情况一样,可能会在前一个仍在解析时生成权限请求,
    2. 在更复杂的应用程序中,应用程序逻辑的多个部分可能需要访问 Geolocator 的位置。因此,请确保您知道代码的哪些部分正在调用 Location 以及何时......

    【讨论】:

      【解决方案2】:

      将期货放入 Future.wait 意味着它们将并行执行。 因此,首先要获得许可,然后是您需要在彼此之后执行它们的位置,例如使用异步等待:

      Future<returntype> gerJobs(JobList currentListOfJobs) async{
        await geolocationPermission;
        final location = await geolocation;
        jobs = await currentListOfJobs.getCurrentJobList(location);
        return jobs
      }
      

      【讨论】:

      • 嗨 - 谢谢。这个解决方案非常合乎逻辑和优雅,但它对我不起作用。我认为这可能是因为“fetchJobsFuture”也需要位置,这样我一次仍然会收到两个请求。知道如何在不重建我的大部分代码的情况下纠正这个问题吗?
      • 那么你也可以在定位之后等待那个调用
      • 嗯 - 即使在等待职位的构建然后调用 fetchJobsFuture 之后,我也被卡住了。我很茫然。这是我尝试过的:getUserPosition().then((value) =&gt; userPosition = value).then((_) { fetchJobsFuture = currentListOfJobs.getCurrentJobList(); }); 现在我使用具有一个未来的 FutureBuilder,并且按原样提供位置。
      • 帖子现已更新为最新代码。任何进一步的指导将不胜感激:) 谢谢彼得!
      • 您现在在构建方法中调用未来,这不是您想要做的事情(构建方法不应该有任何副作用。而是像我将在编辑中那样更新您的方法我的回答
      【解决方案3】:

      这是有人建议的解决方案 - 谢谢。卡特琳娜! Future.wait[] 对我不起作用,因为我的 JobList 未来也调用了位置,所以我遇到了同时调用 Geolocator 及其权限的冲突。在这种情况下,答案是将 FutureBuilders 嵌套在另一个中,而不是使用 Future.wait[] 以便一个未来在另一个之前解决。 下面的代码是一个相当草率和不优雅的例子——请原谅,但它传达了我希望的观点:

      class HomePage extends StatefulWidget {
        @override
        _HomePageState createState() => _HomePageState();
      }
      
      class _HomePageState extends State<HomePage> {
        JobList currentListOfJobs;
      
        @override
        void initState() {
          currentListOfJobs = Provider.of<JobList>(context, listen: false);
          super.initState();
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            backgroundColor: Colors.white,
            body: FutureBuilder(
                future: Geolocator.getCurrentPosition(),
                builder: (context, AsyncSnapshot<Position> positionSnapshot) {
                  if (positionSnapshot.connectionState != ConnectionState.done) {
                    return Center(
                      child: CircularProgressIndicator(),
                    );
                  } else {
                    return FutureBuilder(
                        future: currentListOfJobs.getCurrentJobList(),
                        builder:
                            (context, AsyncSnapshot<JobList> jobListFutureSnaphot) {
                          if (jobListFutureSnaphot.connectionState !=
                              ConnectionState.done) {
                            return Center(
                              child: CircularProgressIndicator(),
                            );
                          } else {
                            return Column(
                              mainAxisSize: MainAxisSize.max,
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                SizedBox(
                                  height: 200,
                                  child: Container(
                                    child: MapCardWithMarkers(
                                      heightRemainingForMap: 200,
                                      latitude: positionSnapshot.data.latitude,
                                      longitude: positionSnapshot.data.longitude,
                                      currentJobList: jobListFutureSnaphot.data,
                                    ),
                                  ),
                                ),
                                SizedBox(
                                  height: 200,
                                  child: ListCard(
                                    listTopBarHeight: 20,
                                    jobList: jobListFutureSnaphot.data,
                                  ),
                                ),
                              ],
                            );
                          }
                        });
                  }
                }),
          );
        }
      }
      

      【讨论】:

      • 你不应该像这样嵌套未来的构建器,这个逻辑不属于小部件树(你不想用加载指示器重复自己)
      • 感谢您的评论。我知道这两个缺点 - 在构建方法中嵌套和调用未来。我会玩这个,但我想我的下一步将是 Qubit / BLOC。
      猜你喜欢
      • 2019-08-14
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2019-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      相关资源
      最近更新 更多