Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter FutureBuilder not updating when setState() is called

I have a DataProvider and a FutureBuilder.

class _UserHeaderState extends State<UserHeader> {

  @override
  Widget build(BuildContext context) {
    var _dataProvider = context.watch<DataProvider>();
    var _userProfile = _dataProvider.getUserProfile();

    return FutureBuilder<UserProfile>(
      future: _userProfile,
      builder: (context, snapshot) {
...

My DataProvider.photoURL has profile URL and DataProvider.updatePhotoURL() updates it. DataProvider.getUserProfile() returns UserProfile class, and UserProfile.name is user's name and so on.

I made a button to update profile image using imagepicker. In onPressed, I wrapped DataProvider.updatePhotoURL(); and _userProfile = DataProvider.getUserProfile(); with setState.

Desired output is that when the user selects photo from imagepicker my CircleAvatar should show the newly picked photo right away.

Actual output is that CircleAvatar shows the old photo until I hit hot reload or visits another page and comeback.

Seems like combination of setState() and FutureBuilder snapshot is messed up, but can't figure out how to fix it.

Entire code is below. (excluding DataProvider and UserProfile class)

class UserHeader extends StatefulWidget {

  @override
  _UserHeaderState createState() => _UserHeaderState();
}

class _UserHeaderState extends State<UserHeader> {

  @override
  Widget build(BuildContext context) {
    var _dataProvider = context.watch<DataProvider>();
    var _userProfile = _dataProvider.getUserProfile();

    return FutureBuilder<UserProfile>(
      future: _userProfile,
      builder: (context, snapshot) {
        Widget body = Center(child: null);

        if (snapshot.hasError) {
          print(snapshot.error);
          body = Center(child: ErrorPage(context));
        } else if (!snapshot.hasData) {
          body = Center(child: CircularProgressIndicator());
        } else {
          body = Padding(
            padding: EdgeInsets.all(16),
            child: Row(
                children: [
                  CircleAvatar(
                    backgroundImage: NetworkImage(snapshot.data!.photoURL),
                    radius: 40,
                    child: Stack(
                        children: [
                          Align(
                            alignment: Alignment.bottomRight,
                            child: RawMaterialButton(
                              elevation: 1.0,
                              fillColor: Colors.grey[800],
                              child: Icon(Icons.add_a_photo_rounded, size: 16),
                              shape: CircleBorder(),
                              materialTapTargetSize: MaterialTapTargetSize
                                  .shrinkWrap,
                              padding: EdgeInsets.all(6),
                              constraints: BoxConstraints(minWidth: 0),
                              onPressed: () {
                                print('update photo button pressed');
                                setState(() {
                                  _dataProvider.updatePhotoURL();
                                  _userProfile = _dataProvider.getUserProfile();
                                });
                              },
                            ),
                          )
                        ]
                    ),
                  ),
                ],
              ),
          );
        }
        return body;
      }
    );
  }
}
like image 274
Younghak Jang Avatar asked Oct 20 '25 04:10

Younghak Jang


1 Answers

I encoutered this same problem before...

When you change the definition of Future (in _userProfile), you expect the future to update... but nothing happens...

The reason is that the Future will NOT update the snapshot.hasError, nor snapshot.hasData nor the else... The only thing that changes is ConnectionState.done

Solution:

add a new condition after if (snapshot.hasError) that will include ConnectionState.done. Then when you setState, it will rebuild properly

More information in this excellent explanation

Let me know if you still have trouble.

like image 71
Canada2000 Avatar answered Oct 22 '25 17:10

Canada2000



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!