Hi I am quite new to flutter, and just learned about the Provider package. I want to be able to update my selectionSet (the ingredients the user has selected). I update it in two ways — through typing in a textfieldsearch and through taking a picture. The picture returns a list of predicted ingredients. The textfieldsearch works, but the image does not update the selectionSet across widgets. It is returning the correct list, and the selectionSet is updated within the DisplayPictureScreen, but the selectionSet in IngredientsInput is unchanged.
main.dart — I have also tried wrapping with ChangeNotifierProvider.value
Future<void> main() async {
runApp(
ChangeNotifierProvider(
create: (context) => IngredientSelection(),
child: MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch(
primarySwatch: Colors.green,
),
),
home: TossUp(),
),
),
);
}
ingredient_selection.dart
class IngredientSelection extends ChangeNotifier {
Set<String> selectionSet = {};
void add(String ingredient) {
selectionSet.add(ingredient);
notifyListeners();
}
void addAll(List<String> ingredients) {
selectionSet.addAll(ingredients);
notifyListeners();
}
}
display_picture_screen.dart — part of interest is in the elevated button
class DisplayPictureScreen extends StatelessWidget {
DisplayPictureScreen({super.key, required this.picture});
final XFile picture;
final IngredientsClassifier classifier = IngredientsClassifier();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Preview Page')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.file(File(picture.path), fit: BoxFit.cover, width: 250),
const SizedBox(height: 24),
ElevatedButton(
onPressed: (
() async {
var ingredientSelection = context.read<IngredientSelection>();
List<String> ingredients = await classifier.getPicIngredients(picture);
ingredientSelection.addAll(ingredients);
print("After: ${ingredientSelection.selectionSet}"); //returns correctly
Navigator.pop(context);
Navigator.pop(context);
}
),
child: Text("get ingredients")
)
]
),
),
);
}
}
ingredients_input.dart — I have also tried to wrap viewSelections return with Consumer
class IngredientsInput extends StatefulWidget {
IngredientsInput({super.key});
@override
State<IngredientsInput> createState() {
return _IngredientsInput();
}
}
class _IngredientsInput extends State<IngredientsInput> {
//...other code
Widget viewSelections() {
IngredientSelection ingredientSelection;
ingredientSelection = Provider.of<IngredientSelection>(context);
//var ingredientSelection = context.watch<IngredientSelection>();
print(ingredientSelection.selectionSet);
if(ingredientSelection.selectionSet.isNotEmpty) {
return Container(
height: 400,
child: ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: ingredientSelection.selectionSet.length,
itemBuilder: (BuildContext context, int i) {
return Container(
height: 40,
child: Center(
child: Text(
ingredientSelection.selectionSet.elementAt(i),
style: TextStyle(fontSize: 20),
),
)
);
}
),
);
}
return SizedBox(height: 400,);
}
@override
void dispose() {
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextFieldSearch(
initialList: _ingredientsList,
label: label,
controller: myController,
),
Consumer(
builder: (context, ingredientSelection, child) {
return viewSelections();
}
)
],
);
}
}
Any help greatly appreciated
I have tried to play around with consumers and provider.of and context.read/watch. All of them have the same result: Un-updated set in IngredientsInput, yet updated set in DisplayPictureScreen
2
Answers
Inside
viewSelections()
, notice how you’re taking thecontext
of theState
rather than theConsumer
.In fact, the
context
from yourConsumer
is not being used at all.You should move the code inside
viewSelections()
to theConsumer
‘sbuilder
, so the provider will take thecontext
from theConsumer
.Currently ingredientSelection is not listening for changes so it can’t update.
Change
to