Dans mon application, je crée une liste d'objets en utilisant les données de Firebase. À l'intérieur d'un StreamBuilder, je vérifie si l'instantané contient des données. Si ce n'est pas le cas, je renvoie un simple widget Texte avec "Chargement ...". Mon problème est que si je vais sur une autre page de l'application, puis que je reviens, vous pouvez voir pendant une fraction de seconde qu'il dit `` Chargement ... '' au milieu de l'écran, et c'est un peu irritant. Je suis sûr qu'il télécharge les données depuis Firebase et crée le widget à chaque fois que je reviens sur cette page. Et si je ne vérifie pas les données, cela me donne une donnée que j'essaie d'accéder aux données de null.
Existe-t-il un moyen de mettre en cache les données qui ont déjà été téléchargées, et s'il n'y a eu aucun changement dans les données de Firebase, alors il suffit d'utiliser les données mises en cache?
Voici une version expurgée de mon code:
class Schedule extends StatefulWidget implements AppPage {
final Color color = Colors.green;
@override
_ScheduleState createState() => _ScheduleState();
}
class _ScheduleState extends State<Schedule> {
List<Event> events;
List<Event> dayEvents;
int currentDay;
Widget itemBuilder(BuildContext context, int index) {
// Some Code
}
@override
Widget build(BuildContext context) {
return Center(
child: StreamBuilder(
stream: Firestore.instance.collection('events').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("Loading...");
}
events = new List(snapshot.data.documents.length);
for (int i = 0; i < snapshot.data.documents.length; i++) {
DocumentSnapshot doc = snapshot.data.documents.elementAt(i);
events[i] = Event(
name: doc["name"],
start: DateTime(
doc["startTime"].year,
doc["startTime"].month,
doc["startTime"].day,
doc["startTime"].hour,
doc["startTime"].minute,
),
end: DateTime(
doc["endTime"].year,
doc["endTime"].month,
doc["endTime"].day,
doc["endTime"].hour,
doc["endTime"].minute,
),
buildingDoc: doc["location"],
type: doc["type"],
);
}
events.sort((a, b) => a.start.compareTo(b.start));
dayEvents = events.where((Event e) {
return e.start.day == currentDay;
}).toList();
return ListView.builder(
itemBuilder: itemBuilder,
itemCount: dayEvents.length,
);
},
),
);
}
}
Pour être sûr que les données proviennent du cache local de Firestore ou du réseau, vous pouvez le faire:
for (int i = 0; i < snapshot.data.documents.length; i++) {
DocumentSnapshot doc = snapshot.data.documents.elementAt(i);
print(doc.metadata.isFromCache ? "NOT FROM NETWORK" : "FROM NETWORK");
Dans le cas que vous venez de décrire, vous verrez probablement toujours l'écran de chargement lorsque celui-ci "NE SERA PAS DU RÉSEAU". En effet, cela prend un certain temps pour l'obtenir à partir du cache local. Bientôt, vous pourrez demander les métadonnées de la requête pour les cas avec des résultats vides.
Comme d'autres l'ont suggéré, vous pouvez mettre en cache les résultats et vous ne le verrez pas. Vous pouvez d'abord essayer de le mettre en cache dans le Widget en utilisant quelque chose comme:
QuerySnapshot cache; //**
@override
Widget build(BuildContext context) {
return Center(
child: StreamBuilder(
initialData: cache, //**
stream: Firestore.instance.collection('events').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("Loading...");
}
cache = snapshot.data; //**
Cela fera que votre widget se souviendra des données. Cependant, si cela ne résout pas votre problème, vous devrez l'enregistrer non pas dans ce widget mais ailleurs. Une option consiste à utiliser le widget Provider
pour le stocker dans une variable qui dépasse la portée de ce widget particulier.
Probablement pas lié, mais c'est aussi une bonne idée de déplacer la Firestore.instance.collection('events').snapshots()
vers initState()
, d'enregistrer la référence au flux dans un champ privé et de l'utiliser StreamBuilder
. Sinon, à chaque build (), vous pouvez créer un nouveau flux. Vous devez être prêt pour les appels build()
qui se produisent plusieurs fois par seconde, quelle qu'en soit la raison.