Reputation: 105
I'm pretty new to flutter and really, really want to use provider to pass data around, but I just can't get it to work. I think I have everything set right, but for some reason when I notify listeners, my app doesn't refresh. All I'm trying to do is update a profile pic. I start with a pic that is in firebase (works fine). Then I give the user the option to update their pic with camera or photos. When they choose a new pic, the consumer doesn't update like I would expect it to. Can someone please tell me if I'm doing something wrong or how I may be able to accomplish this?
First, here is my main:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<Storage>(create: (context) => Storage()),
StreamProvider<Uid>.value(value: AuthService().user),
],
child: MaterialApp( ....
Then here is the class and method that updates the photo URL which I call from an image picker class. I'm passing context so I can pop that image picker view and go back to the profile page after it's done.
class Storage with ChangeNotifier {
String userPhotoUrl;
void uploadImage(PickedFile _imageFile, BuildContext context) async {
.... //some other code here
try {
var snapshot =
await _storage.ref().child('/profileImages/$_userId').putFile(file);
await snapshot.ref.getDownloadURL().then((value) {
userPhotoUrl = value;
notifyListeners();
print(userPhotoUrl); //I know the code is working because it prints here
Navigator.pop(context);
});
} catch (e) {
print(e);
}
}
}
And here is the profile page that I'm trying to update. It's just not getting the updated value.
class Profile extends StatefulWidget {
Profile({Key key}) : super(key: key);
@override
_ProfileState createState() => _ProfileState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _ProfileState extends State<Profile> with TickerProviderStateMixin {
String imageUrl; //firebase pic to start - works fine
@override
Widget build(BuildContext context) {
....//some more widget tree
Consumer<Storage>(
builder: (context, storage, widget) =>
CircularProfileAvatar( //never updates. userPhotoURL always null
storage.userPhotoUrl ?? imageUrl, //always uses imageUrl,
elevation: 20,
borderColor: Colors.white70,
borderWidth: 1,
radius: 50,
),
),
Any idea as to why it's not working? I would think this should be easy but provider is still alluding me...
Upvotes: 4
Views: 3128
Reputation: 1713
You are using the wrong approach to solve the problem you need to do some like this
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChangeNotifierProvider<Storage>(
create: (context) => Storage(),
child: ImageGrabberScreen(),
),
),
);
When navigating to the screen you want to use the Consumer()
widget
By using Provider or MultipleProvider as parent you're telling flutter you want to use StreamBuilder()
widget but from your work I see you're using the Consumer()
widget
Also try to do trigger your function doing the below
Widget build(BuildContext context) {
var storageNotifier = Provider.of<Storage>(context);
///In your button you can then do storageNotifier.uploadImage();
}
This type of problem is best solved with FutureBuilder
if you don't have any form of button that is meant to trigger this event
Future<String> uploadImage() async {
.... //some other code here
var snapshot =
await _storage.ref().child('/profileImages/$_userId').putFile(file);
return await snapshot.ref.getDownloadURL();
}
Then somewhere in the widget tree do this
FutureBuilder(
future: uploadImage(),
builder: (_,snapshot){
if(snapshot.hasData){
return CircularProfileAvatar(snapshot.data);
}else{
return CircularProfileAvatar(imageUrl);
}
})
...widget tree continues
Upvotes: 1