I'm trying to learn some flutter programming and I'm facing a problem, when I run the program I don't get the information on the screen at the first time, I mean the data is retreived from firestore but I have to reload the page several times to show the data on the screen, what might be happening I am using FutureBuilder
pet_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:histovet/src/controller/pet_controller.dart';
import 'package:histovet/src/models/pet_model.dart';
import 'package:histovet/src/pages/widgets/menu_lateral.dart';
import 'package:histovet/src/pages/pet/add_pets.dart';
import 'package:histovet/src/pages/pet/pet_update.dart';
// Clases encargadas de la vista donde se enlistan todas las ventas que existan en la
// base de datos
class PetsPage extends StatefulWidget {
static String id = "pets_page";
const PetsPage({Key? key}) : super(key: key);
@override
State<PetsPage> createState() => _PetsPageState();
}
class _PetsPageState extends State<PetsPage> {
TextStyle txtStyle = const TextStyle(
fontWeight: FontWeight.w900, fontSize: 30, color: Colors.black);
PetController petCont = PetController();
bool answer = false;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Mascotas"),
actions: [
IconButton(
onPressed: () {
setState(() {});
},
icon: const Icon(Icons.refresh))
],
),
//drawer: const MenuLateral(),
floatingActionButton: FloatingActionButton.extended(
icon: const Icon(FontAwesomeIcons.plus),
label: const Text('Registrar nueva mascota'),
elevation: 15.0,
backgroundColor: Colors.blue,
onPressed: () {
Navigator.pushNamed(context, AddPet.id);
}),
body: FutureBuilder(
future: petCont.allPets(),
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
if (snapshot.hasError) {
print("error");
return const Text('Error');
} else if (snapshot.hasData) {
List species = snapshot.data ??[];
print(species);
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
for (Pet specie in species)
Card(
margin: const EdgeInsets.all(6),
elevation: 6,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/fondo.jpg'),
fit: BoxFit.cover,
opacity: 0.3),
),
child: ListTile(
onLongPress: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UpdatePet(
specie.id.toString(),
specie.owner.toString())));
},
leading: const Icon(
FontAwesomeIcons.paw,
color: Colors.black,
),
title: Text(
specie.name,
style: txtStyle,
),
subtitle: Text(
specie.specie,
style: txtStyle.copyWith(fontSize: 17),
),
trailing: IconButton(
icon: const Icon(Icons.delete,
color: Colors.black),
onPressed: () {
messageDelete(specie.id.toString());
Navigator.pushNamed(context, '/pets')
.then((_) => setState(() {}));
},
))),
)
],
),
);
} else {
return const Text('Empty data');
}
})),
);
}
// Le indica al usuario si se pudo o no eliminar el registro
void messageDelete(String idPet) async {
answer = await petCont.deletePet(idPet);
if (answer) {
Navigator.pushNamed(context, '/pets').then((_) => setState(() {}));
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("Se eliminó el registro de la mascota"),
backgroundColor: Colors.green,
));
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text("No se pudo eliminar el registro de la mascota"),
backgroundColor: Colors.green,
));
}
}
}
pet_controller.dart
Future<List<Pet>> allPets() async {
try{
_pets = await _service.getPetsBD();
return _pets;
} catch (e) {
return _pets;
}
}
pet_service.dart
Future<List<Pet>> getPetsBD() async {
List<Pet> mascotas = [];
final FirebaseAuth auth = FirebaseAuth.instance;
final User? user = auth.currentUser;
final uid = user?.uid;
try {
final collection = FirebaseFirestore.instance
.collection('pets')
.where('owner', isEqualTo: uid);
collection.snapshots().listen((querySnapshot) {
for (var doc in querySnapshot.docs) {
Map<String, dynamic> data = doc.data();
Pet newPet = Pet(
data["id"],
data["owner"],
data["birthday"].toString(),
data["name"],
data["neutering"],
data["age"],
data["breed"],
data["specie"],
data["color"],
data["gender"],
data["clinic"]);
mascotas.add(newPet);
}
});
return mascotas;
} catch (e) {
return mascotas;
}
}
CodePudding user response:
Please try;
List species = snapshot.data ??[];
to
List species = snapshot.data() ??[];
CodePudding user response:
It looks like the FutureBuilder widget is not being rebuilt when new data is available. This is likely because the Future returned by petCont.allPets() is not changing.
You can fix this by providing a new Future to the FutureBuilder each time the widget is rebuilt. For example, you could use a StatefulWidget and store the Future in the widget's state. Then, in the build method, you can return a new FutureBuilder with the updated Future each time the widget is rebuilt. This will cause the FutureBuilder to rebuild and display the updated data.
Here is an example of how this could be implemented:
class _PetsPageState extends State<PetsPage> {
PetController petCont = PetController();
Future<List<Pet>> _future;
@override
void initState() {
super.initState();
_future = petCont.allPets();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Mascotas"),
actions: [
IconButton(
onPressed: () {
setState(() {
_future = petCont.allPets();
});
},
icon: const Icon(Icons.refresh))
],
),
body: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
if (snapshot.hasError) {
print("error");
return const Text('Error');
} else if (snapshot.hasData) {
List species = snapshot.data ??[];
print(species);
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
for (Pet specie in species)
Card(
margin: const EdgeInsets.all(6),
elevation: 6,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/fondo.jpg'),
fit: BoxFit.cover,
opacity: 0.3),
),
child: ListTile(
// ...
),
),
),
],
),
);
}
return const CircularProgressIndicator();
},
),
floatingActionButton: FloatingActionButton.extended(
icon: const Icon(FontAwesomeIcons.plus),
label: const Text('Registrar nueva mascota'),
elevation: 15.0,
backgroundColor: Colors.blue,
onPressed: () {
Navigator.pushNamed(context, AddPet.id);
}),
),
);
}
}
In the code above, the Future returned by petCont.allPets() is stored in a StatefulWidget's state, and a new FutureBuilder is returned in the build method
I hope that's useful, check out my Bio!