title: Provider Object Requests Rebuild During Existing Build
body: <p>I'm learning Provider and my test app draws images from a Firestore database into a ListView. I'd like a LongPress on <em>any</em> image to make the <em>whole</em> list <em>toggle</em> and redraw with checkbox selector icons, as below, similar to the way the gallery works:</p>
  <img src="https://i.stack.imgur.com/TAYEb.jpg" width="300" >
  <p>My code works, but it throws an exception on every LongPress stating that &quot;<strong>setState() or markNeedsBuild() was called during build</strong>,&quot; and I'm pulling my hair out trying to figure out how to either delay the ChangeNotifier until the widget tree is built? Or some other way to accomplish this task?</p>
  <p>My Provider class simply accepts a List of my <strong>PictureModel</strong> class and has a <strong>toggleSelectors()</strong> method which notifies listeners. Here's the code:</p>
  <pre><code>class PicturesProvider with ChangeNotifier {
    List&lt;PictureModel&gt; _pictures = [];
    bool visible = false;
  
    UnmodifiableListView&lt;PictureModel&gt; get allPictures =&gt; UnmodifiableListView(_pictures);
    UnmodifiableListView&lt;PictureModel&gt; get selectedPictures =&gt;
        UnmodifiableListView(_pictures.where((pic) =&gt; pic.selected));
  
    void addPictures(List&lt;PictureModel&gt; picList) {
      _pictures.addAll(picList);
      notifyListeners();
    }
  
    void toggleSelectors() {
      visible = !visible;
      _pictures.forEach((pic) {
        pic.selectVisible = visible;
      });
      notifyListeners();
    }
  }
  
  </code></pre>
  <p>I have a <strong>SinglePicture</strong> UI class that loads a network image into an AspectRatio widget and wraps it with a GestureDetector to toggle the selectors and present them on the top of a Stack widget, like so:</p>
  <pre><code>Widget build(BuildContext context) {
      int originalHeight, originalWidth;
      return AspectRatio(
        aspectRatio: pictureModel.aspectRatio,
        child: Stack(
          fit: StackFit.expand,
          children: &lt;Widget&gt;[
            FutureBuilder&lt;ui.Image&gt;(
              future: _getImage(),
              builder: (BuildContext context, AsyncSnapshot&lt;ui.Image&gt; snapshot) {
                if (snapshot.hasData) {
                  ui.Image image = snapshot.data;
                  originalHeight = image.height;
                  originalWidth = image.width;
                  return GestureDetector(
                    onLongPress: () =&gt; Provider.of&lt;PicturesProvider&gt;(context, listen: false).toggleSelectors(),
                    child: RawImage(
                      image: image,
                      fit: BoxFit.cover,
                      // if portrait image, move down slightly for headroom
                      alignment: Alignment(0, originalHeight &gt; originalWidth ? -0.2 : 0),
                    ),
                  );
                } else {
                  return Center(child: CircularProgressIndicator());
                }
              },
            ),
            Positioned(
              left: 10.0,
              top: 10.0,
              child: pictureModel.selectVisible == false
                  ? Container(
                      height: 0.0,
                      width: 0.0,
                    )
                  : pictureModel.selected == false
                      ? Icon(
                          Icons.check_box_outline_blank,
                          size: 30.0,
                          color: Colors.white,
                        )
                      : Icon(
                          Icons.check_box,
                          size: 30.0,
                          color: Colors.white,
                        ),
            )
          ],
        ),
      );
    }
  </code></pre>
  <p>This <strong>SinglePicture</strong> class is then called from my <strong>PicturesList</strong> UI class which simply builds a ListView, like so:</p>
  <pre><code>class PicturesList extends StatelessWidget {
    final List&lt;PictureModel&gt; pictures;
    PicturesList({@required this.pictures});
    @override
    Widget build(BuildContext context) {
      return ListView.builder(
        itemCount: pictures.length,
        cacheExtent: 3,
        itemBuilder: (context, index) {
          return SinglePicture(
            pictureModel: pictures[index],
          );
        },
      );
    }
  </code></pre>
  <p>The whole shebang is then called from a FutureBuilder in my app, which builds the app, like so:</p>
  <pre><code>body: FutureBuilder(
    future: appProject.fetchProject(), // Snapshot of database
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      if (snapshot.hasData) {
        // Get all picture URLs from project snapshot
        List&lt;dynamic&gt; picUrls = snapshot.data['pictures'].map((pic) =&gt; pic['pic_cloud']).toList();
        // Create list of PictureModel objects for Provider
        List&lt;PictureModel&gt; pictures = picUrls.map((url) =&gt; PictureModel(imageUrl: url, imageHeight: 250.0, selectVisible: false)).toList();
        // Add list of PictureModel objects to Provider for UI render
        context.watch&lt;PicturesProvider&gt;().addPictures(pictures);
        return SafeArea(
          child: PicturesList(
            pictures: context.watch&lt;PicturesProvider&gt;().allPictures,
          ),
        );
      } else if (snapshot.hasError) {
        print('Error');
      } else {
        return Center(
          child: CircularProgressIndicator(),
        );
      }
    },
  ),
  </code></pre>
  <p>Please, if anybody has a hint about how I can accomplish this toggle action without throwing exceptions, I'd be very grateful. Thank you in advance!</p>