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.
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();
}
où 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
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
);
}
}