web-dev-qa-db-fra.com

Récupérer automatiquement les données Api avec intervalle dans Flutter

Sur mon application Flutter, j'essaie d'afficher les données de mise à jour. Je réussis à obtenir manuellement les données de l'API météo. Mais je dois constamment saisir des données toutes les 5 secondes. Il devrait donc être mis à jour automatiquement. Voici mon code dans Flutter:

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sakarya Hava',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Sakarya Hava'),
        ),
        body: Center(
          child: FutureBuilder<SakaryaAir>(
            future: getSakaryaAir(), //sets the getSakaryaAir method as the expected Future
            builder: (context, snapshot) {
              if (snapshot.hasData) { //checks if the response returns valid data
                return Center(
                  child: Column(
                    children: <Widget>[
                      Text("${snapshot.data.temp}"), //displays the temperature
                      SizedBox(
                        height: 10.0,
                      ),
                      Text(" - ${snapshot.data.humidity}"), //displays the humidity
                    ],
                  ),
                );
              } else if (snapshot.hasError) { //checks if the response throws an error
                return Text("${snapshot.error}");
              }
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }


  Future<SakaryaAir> getSakaryaAir() async {
    String url = 'http://api.openweathermap.org/data/2.5/weather?id=740352&APPID=6ccf09034c9f8b587c47133a646f0e8a';
    final response =
    await http.get(url, headers: {"Accept": "application/json"});


    if (response.statusCode == 200) {
      return SakaryaAir.fromJson(json.decode(response.body));
    } else {
      throw Exception('Failed to load post');
    }
  }
}

J'ai trouvé un tel extrait pour bénéficier de:

// runs every 5 second
Timer.periodic(new Duration(seconds: 5), (timer) {
   debugPrint(timer.tick);
});

J'ai probablement besoin de terminer et d'appeler FutureBuilder avec cet extrait de code, mais je n'ai pas été en mesure de comprendre comment le faire.

4
Şansal Birbaş

Vous pouvez refactoriser votre FutureBuilder pour utiliser une variable Future au lieu d'appeler la méthode dans le FutureBuilder. Cela vous obligerait à utiliser un StatefulWidget et vous pouvez configurer le futur dans votre initState et le mettre à jour en appelant setState.

Vous avez donc un futur champ variable comme:

Future< SakaryaAir> _future;

Ainsi, votre initState ressemblerait à ceci:

@override
  void initState() {
    super.initState();
    setUpTimedFetch();
  }

setUpTimedFetch est défini comme

  setUpTimedFetch() {
    Timer.periodic(Duration(milliseconds: 5000), (timer) {
      setState(() {
        _future = getSakaryaAir();
      });
    });
  }

Enfin, votre FutureBuilder sera remplacé par:

FutureBuilder<SakaryaAir>(
          future: _future,
          builder: (context, snapshot) {
            //Rest of your code
          }),

Voici une démo de DartPad: https://dartpad.dev/2f937d27a9fffd8f59ccf08221b82be

1
Victor Eronmosele

Les contrats à terme peuvent avoir 2 états: terminés ou inachevés. Les Futures ne peuvent pas "progresser", mais les Streams le peuvent, donc pour votre cas d'utilisation, les Streams ont plus de sens.

Vous pouvez les utiliser comme ceci:

Stream.periodic(Duration(seconds: 5)).asyncMap((i) => getSakaryaAir())

périodique émet des événements vides toutes les 5 secondes et nous utilisons asyncMap pour mapper cet événement dans un autre flux, ce qui nous donne les données.

Voici un exemple de travail:

import 'package:flutter/material.Dart';
import 'package:http/http.Dart' as http;

class ExamplePage extends StatelessWidget {
  Future<String> getSakaryaAir() async {
    String url =
        'https://www.random.org/integers/?num=1&min=1&max=6&col=1&base=10&format=plain&rnd=new';
    final response =
        await http.get(url, headers: {"Accept": "application/json"});

    return response.body;
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: Stream.periodic(Duration(seconds: 5))
          .asyncMap((i) => getSakaryaAir()), // i is null here (check periodic docs)
      builder: (context, snapshot) => Text(snapshot.data.toString()), // builder should also handle the case when data is not fetched yet
    );
  }
}
3
pr0gramist