Dhouib Omar
Dhouib Omar

Reputation: 35

How can i pass snapshot data from futurebuilder to another futurebuilder in the same page?


I'm new to the flutter world and mobile app development and struggling with how I should pass data throughout my app. This is my code, How can I pass snapshot data from futurebuilder to another futurebuilder on the same page? help, please **Widget _buildProgrammCard()**
From this widget Card I need to pass the location id which is in the futurebuilder to another 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(
                    ),
                    );
                  }
              ),
            ),
    );
  }

Widget build(BuildContext context)
And this is the second Widget that I need to pass the location id into it from another widget.

 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(
                ),
                );
              }
          ),
    );
  }

Upvotes: 1

Views: 3756

Answers (2)

Dhouib Omar
Dhouib Omar

Reputation: 35

Thanks Baker for your response but not exactly what i meant these are my two futures and my class

This is my future that returns the Location from her i need to pass the location id to the another future

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');
    }
  }

This is my future that returns List of weather that depends on location 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);
  }

This is my class Location

// 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,
  };
}

and this is my homePage

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'],
                  ),
                ),
              ],
            ),
          ),
        );
      },
    ),

  }
}

Finaly i need to get the location id from the first future that return Location to the second future Getweither(String ID) .

Upvotes: 0

Baker
Baker

Reputation: 28050

Flutter rebuilds widgets often so FutureBuilder shouldn't call a future function directly. (A widget may call its build function up to 60 times a second.)

Instead a FutureBuilder should only receive a future value from an async function called elsewhere.

In a StatefulWidget, the most common place to initiate long-running operations is in its initState() method.

The location data, retrieved during the first Widget initState, can be passed to the second widget, just like a regular constructor argument.

You'll access it in the 2nd widget's State class with 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...');
      },
    );
  }
}

State Management Solutions

When you get tired of passing values around like in the above example, you can use a State Management package or create your own that suits your needs.

Here's a nice overview from Jeff Delaney about various options: https://fireship.io/lessons/flutter-state-management-guide/

And also check out Get which isn't mentioned in the above: https://pub.dev/packages/get

Some of the above State management solutions (e.g. Provider) help you use Flutter-native state functionality correctly (because its rather complicated), while others completely avoid that and provide a framework separate from the Widget lifecycle (e.g. Get).

Upvotes: 3

Related Questions