【问题标题】:How can i pass snapshot data from futurebuilder to another futurebuilder in the same page?如何将快照数据从 futurebuilder 传递到同一页面中的另一个 futurebuilder?
【发布时间】:2021-04-13 18:18:54
【问题描述】:

我是 Flutter 世界和移动应用程序开发的新手,并且正在为如何在我的应用程序中传递数据而苦苦挣扎。这是我的代码,如何将快照数据从 futurebuilder 传递到同一页面上的另一个 futurebuilder?请帮忙 **小部件 _buildProgrammCard()**
从这个小部件卡中,我需要将 futurebuilder 中的位置 ID 传递给另一个 futurebuilder。
Widget _buildProgrammCard() {
    return Container(
        height: 90,
       child:
            Card(
              semanticContainer: true,
              clipBehavior: Clip.antiAliasWithSaveLayer,
              color: Colors.white,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(10.0),
              ),
              elevation: 4,
              margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
              child:
              FutureBuilder(
                  future: databaseHelper2.Lastlocation(),
                  builder: (context,snapshot) {
                    if (snapshot.hasError)
                    {
                      print(snapshot.error);
                      print("there is problem");
                    }
                    return snapshot.hasData
                        ?  Text("Location :" +snapshot.data.id)
                        :  Center(child: CircularProgressIndicator(
                    ),
                    );
                  }
              ),
            ),
    );
  }

小部件构建(BuildContext 上下文)
这是我需要将位置 ID 从另一个小部件传递给它的第二个小部件。

 Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      body: FutureBuilder(
              future: databaseHelper2.Getweither(location_id),
              builder: (context,snapshot) {
                if (snapshot.hasError)
                {
                  print(snapshot.error);
                  print("there is problem !");
                }
                return snapshot.hasData
                    ?  ItemList(list: snapshot.data)
                    :  Center(child: CircularProgressIndicator(
                ),
                );
              }
          ),
    );
  }

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    Flutter 经常重建小部件,因此 FutureBuilder 不应直接调用未来函数。 (小部件每秒最多可以调用其build 函数60 次。)

    相反,FutureBuilder 应该只从其他地方调用的异步函数接收未来值。

    在 StatefulWidget 中,启动长时间运行操作的最常见位置是在其 initState() 方法中。

    在第一个 Widget initState 期间检索到的位置数据可以传递给第二个 Widget,就像常规的构造函数参数一样。

    您将在第二个小部件的 State 类中使用 widget.locationId 访问它。

    import 'package:flutter/material.dart';
    
    class FirstFuturePage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => FirstFutureState();
    }
    
    class FirstFutureState extends State<FirstFuturePage> {
      Future<int> locationId = Future.value(-1);
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        someAsyncCall();
      }
    
      Future<void> someAsyncCall() async {
        // just returns the number 0 after 2 seconds & assigns it to "locationId" var
        locationId = Future.delayed(Duration(seconds: 2), () => 0);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Center(
              child: FutureBuilder<int>(
                future: locationId,
                builder: (context, snapshot) {
                  int _locationId = snapshot.data;
                  if (snapshot.hasData)
                    return SecondWidget(_locationId);
                  return Text('Looking up location...');
                },
              ),
            ),
          ),
        );
      }
    }
    
    class SecondWidget extends StatefulWidget {
      final int locationId;
    
      SecondWidget(this.locationId);
    
      @override
      _SecondWidgetState createState() => _SecondWidgetState();
    }
    
    class _SecondWidgetState extends State<SecondWidget> {
      Future<String> weatherData = Future.value('Unknown');
    
      @override
      void initState() {
        super.initState();
        loadWeather(widget.locationId); // Use the locationId passed into widget
      }
    
      /// Takes locationId from First widget and looks up weather data for location
      Future<void> loadWeather(int locationId) async {
        List<String> weatherDataStore = List<String>.from(['Rainy', 'Sunny']);
        weatherData = Future.delayed(
            Duration(seconds: 2), () => weatherDataStore[locationId]
        );
      }
    
      @override
      Widget build(BuildContext context) {
        int _locId = widget.locationId;
        return FutureBuilder<String>(
          future: weatherData,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Text('Weather for location $_locId is: ${snapshot.data}');
            }
            return Text('Loading Weather...');
          },
        );
      }
    }
    

    状态管理解决方案

    当您厌倦了像上面示例中那样传递值时,您可以使用状态管理包或创建适合您需要的自己的包。

    以下是 Jeff Delaney 关于各种选项的精彩概述: https://fireship.io/lessons/flutter-state-management-guide/

    还可以查看上面未提及的 Get: https://pub.dev/packages/get

    上面的一些状态管理解决方案(例如 Provider)帮助您正确使用 Flutter 原生状态功能(因为它相当复杂),而另一些则完全避免了这种情况,并提供了一个独立于 Widget 生命周期的框架(例如 Get)。

    【讨论】:

    • 感谢 Baker 的回复,但不是我的意思!我已经发布了另一个答案来向您解释更多。
    【解决方案2】:

    感谢贝克的回复,但不完全是我的意思 这是我的两个未来和我的班级

    这是我的未来,从她那里返回位置我需要将位置 ID 传递给另一个未来

    Future<Location> Lastlocation() async {
        final prefs = await SharedPreferences.getInstance();
        final key = 'token';
        final value = prefs.get(key) ?? 0;
        String myUrl = "$serverUrl/location/getlastlocation?token=" + value;
        http.Response response = await http.get(
          myUrl,
          headers: {
            'Accept': 'application/json',
            //'Authorization': 'token $value'
          },
        );
        if (response.statusCode == 200) {
          // If the server did return a 200 OK response,
          return Location.fromJson(json.decode(response.body));
        } else {
          // then throw an exception.
          throw Exception('Failed to load album');
        }
      }
    

    这是我的未来,返回取决于位置 ID 的天气列表

     Future<List> Getweither(String ID) async {
        final prefs = await SharedPreferences.getInstance();
        final key = 'token';
        final value = prefs.get(key) ?? 0;
    
        String myUrl = "$serverUrl/sensors/getDeviceByid/$ID?token=" + value;
        http.Response response = await http.get(myUrl,
            headers: {
              'Accept': 'application/json',
            });
        print("myUrldevice :"+myUrl);
        print("status :"+response.statusCode.toString());
    
        return json.decode(response.body);
      }
    

    这是我的班级位置

    // To parse this JSON data, do
    //
    //     final location = locationFromJson(jsonString);
    
    import 'dart:convert';
    
    List<Location> locationFromJson(String str) => List<Location>.from(json.decode(str).map((x) => Location.fromJson(x)));
    
    String locationToJson(List<Location> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
    
    class Location {
      Location({
        this.automaticIrrigation,
        this.coordinates,
        this.createdDate,
        this.sensorIds,
        this.id,
        this.siteName,
        this.description,
        this.v,
      });
    
      bool automaticIrrigation;
      List<double> coordinates;
      DateTime createdDate;
      List<String> sensorIds;
      String id;
      String siteName;
      String description;
      int v;
    
      factory Location.fromJson(Map<String, dynamic> json) => Location(
        automaticIrrigation: json["AutomaticIrrigation"],
        coordinates: List<double>.from(json["Coordinates"].map((x) => x.toDouble())),
        createdDate: DateTime.parse(json["Created_date"]),
        sensorIds: List<String>.from(json["Sensor_ids"].map((x) => x)),
        id: json["_id"],
        siteName: json["SiteName"],
        description: json["Description"],
        v: json["__v"],
      );
    
      Map<String, dynamic> toJson() => {
        "AutomaticIrrigation": automaticIrrigation,
        "Coordinates": List<dynamic>.from(coordinates.map((x) => x)),
        "Created_date": createdDate.toIso8601String(),
        "Sensor_ids": List<dynamic>.from(sensorIds.map((x) => x)),
        "_id": id,
        "SiteName": siteName,
        "Description": description,
        "__v": v,
      };
    }
    

    这是我的主页

    import 'dart:convert';
    import 'dart:developer';
    import 'package:http/http.dart' as http;
    import 'package:flutter/material.dart';
    import 'package:fluttertoast/fluttertoast.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    import 'package:sidebar_animation/Services/DataHelpers.dart';
    import 'package:sidebar_animation/sidebar/sidebar_layout.dart';
    import '../bloc.navigation_bloc/navigation_bloc.dart';
    import 'package:sidebar_animation/constants.dart';
    import 'package:flutter/gestures.dart';
    import 'package:sidebar_animation/bloc.navigation_bloc/navigation_bloc.dart';
    
    class HomePage extends StatelessWidget with NavigationStates {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
    
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
       DatabaseHelper2 databaseHelper2 = new DatabaseHelper2();
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.grey[100],
          body: ListView(
              FutureBuilder(
                  future: databaseHelper2.Getweither(location_id),
                  builder: (context,snapshot) {
                    if (snapshot.hasError)
                    {
                      print(snapshot.error);
                      print("there is problem !");
                    }
                    return snapshot.hasData
                        ?  ItemList(list: snapshot.data)
                        :  Center(child: CircularProgressIndicator(
                    ),
                    );
                  }
    ),
        );
      }
    
      Widget _buildProgrammCard() {
        return Container(
            height: 90,
           child:
                Card(
                  semanticContainer: true,
                  clipBehavior: Clip.antiAliasWithSaveLayer,
                  color: Colors.white,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10.0),
                  ),
                  elevation: 4,
                  margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
                  child:
                  FutureBuilder(
    //                future: databaseHelper.getData(),
                      future: databaseHelper2.Lastlocation(),
                      builder: (context,snapshot) {
                        if (snapshot.hasError)
                        {
                          print(snapshot.error);
                          print("mochkla lenaa *");
                        }
                        return snapshot.hasData
                            ?  Text("Location :" +snapshot.data.siteName)
                            :  Center(child: CircularProgressIndicator(
                        ),
                        );
                      }
                  ),
                ),
    
        );
    
      }
    
    class ItemList extends StatelessWidget{
      List list;
      ItemList({this.list});
    
      ScrollController _controller = new ScrollController();
    
    
      @override
      Widget build(BuildContext context) {
        return  ListView.builder(
          itemCount: list == null ? 0 : list.length,
          scrollDirection: Axis.horizontal,
          itemExtent: 190.0,
          itemBuilder: (context, index) {
            return Padding(
              padding: const EdgeInsets.fromLTRB(10, 0, 0, 14),
              child: Container(
                decoration: BoxDecoration(
                  image: DecorationImage(
                    image: NetworkImage(
                      item.storyUrl,
                    ),
                    fit: BoxFit.cover,
                    colorFilter: ColorFilter.mode(
                      Colors.black26,
                      BlendMode.darken,
                    ),
                  ),
                  borderRadius: BorderRadius.circular(10.0),
                  color: Colors.grey,
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.all(10.0),
                      child: Text(
                        "temp :",
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    Padding(
                      padding: EdgeInsets.only(left: 24),
                      child:
                      Text(
                        list[i]['Weither']['Temp'],
                      ),
                    ),
                  ],
                ),
              ),
            );
          },
        ),
    
      }
    }
    

    最后我需要从第一个 future 中获取 location id,将 Location 返回到第二个 future Getweither(String ID)

    【讨论】:

    • 嗨 Dhouib,感谢您提供的额外细节。我希望能够引导您朝着在 Flutter 中公开通用设计模式的方向发展,并让您通过更改当前架构来学习/发现直接解决问题的方法。这里有另一个建议:使 _buildProgrammCard 成为它自己的 StatefulWidget 类,这样它就可以在创建时在其 initState 方法中启动 Lastlocation 调用。 (我假设您需要 Lastlocation 数据才能获取天气。)
    • 感谢@baker 的评论。这很有帮助。
    猜你喜欢
    • 2020-09-11
    • 2021-11-17
    • 2020-09-10
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 2020-12-27
    • 2017-01-25
    • 2020-04-02
    相关资源
    最近更新 更多