I am working on an API in Flutter after spending a long time I managed to get the data I am using a provider and change notifier to update my UI. According to the data that I get, but the UI is not updating
This is my API provider:
class ApiProvider extends ChangeNotifier{
List<PlantModel>? _plantList = [];
List<PlantModel>? get plantList => _plantList;
final apiService = ApiServices();
bool isLoading = true;
void getPlantData()async{
if (kDebugMode) {
print("calling...function ");
}
_plantList = await apiService.getPlantDataCall();
isLoading = false;
if (kDebugMode) {
print("notifying listners");
}
notifyListeners();
if (kDebugMode) {
print("listners notified");
print("this is isloading == $isLoading");
}
}
}
and my UI code :
import 'package:better_lucks/controller/api_controller.dart';
import 'package:better_lucks/controller/google_sign_in_controller.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
class Dashboard extends StatelessWidget {
Dashboard({super.key});
@override
Widget build(BuildContext context) {
Provider.of<ApiProvider>(context,listen:false).getPlantData();
final user = FirebaseAuth.instance.currentUser!;
return Scaffold(
backgroundColor: Colors.green,
appBar: AppBar(
backgroundColor: Colors.transparent,
leading:Container(margin: const EdgeInsets.all(12),
child: CircleAvatar(backgroundImage: NetworkImage(user.photoURL!))
),
title: Text(user.displayName.toString(),style:const TextStyle(color:Colors.white),),
actions: [
IconButton(color: Colors.white,
onPressed: (){
final provider = Provider.of<GoogleSignInProvider>(context,listen: false);
provider.logout();
}, icon:const FaIcon(FontAwesomeIcons.arrowRightFromBracket))
],
),
body:Consumer<ApiProvider>(
builder: (context,apiProvider,_){
return SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child:apiProvider.isLoading? GridView.builder(
shrinkWrap: true,
gridDelegate:const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing:8,
crossAxisSpacing: 8
),
itemCount: apiProvider.plantList!.length,
itemBuilder: (BuildContext context,int index){
return Card(
child: Column(
children: [
Container(margin: const EdgeInsets.all(8),
child: CircleAvatar(
backgroundImage:NetworkImage(apiProvider.plantList![index].imageUrl),
radius: 50,
),
),
Text(apiProvider.plantList![index].commonName),
],
),
);
}):const Center(
child: CircularProgressIndicator(),
),
);
},)
);
}
}
Here is the output from terminal:
I/flutter (16721): we got the response body :
I/flutter (16721): [Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel', Instance of 'PlantModel']
I/flutter (16721): notifying listners
I/flutter (16721): listners notified
I/flutter (16721): this is isloading == false
there was no error in the terminal I guess the UI is not updating because I did some mistake, I tried making the listen: true
(located after widget build) when I call to get data but it calls API so many times instead of one.
2
Answers
This means that the widget won’t update when changes occur. Instead, you should use listen: true or omit the listen parameter altogether.
How are you creating your provider and how are you interacting with your ApiProvider?
And how are you updating your provider, or refreshing the data from the api? Only the call Provider.of(context,listen:false).getPlantData(); inside of your build method?
This will only refresh the api data when your widget is already rebuilding and will not work.
Also it looks to me like your child:apiProvider.isLoading? GridView.builder( is the wrong way (displaying the grid when loading is true).
I created a slightly modified example from your code that works like you expect it to. It shows the loading indicator for 2 seconds and then displays one entry. And afterwards you can refresh the api with a button to add more entries. But of course you could also create a Timer inside of a State object of a StatefulWidget that automatically calls refresh every second, or so: