Search code examples
flutterdartflutter-futurebuilder

Flutter FutureBuilder rebuilds unnecessarily when navigate between screens


My FutureBuilder rebuilds unnecessarily when navigate between screens. Each time I have to get the download URL from the Firebase Storage and this results in extremely flickering. How can I prevent that the FutureBuilder rebuilds everytime I navigate between screens?

I already tried the following solutions:

https://medium.com/saugo360/flutter-my-futurebuilder-keeps-firing-6e774830bc2

Flutter Switching to Tab Reloads Widgets and runs FutureBuilder

But without success. With both the FutureBuilder get always rebuild.

This is my code (Attempt 1):

class _GuestbookCardImageState extends State<GuestbookCardImage> {
  final AsyncMemoizer _memoizer = AsyncMemoizer();

  _getFeaturedImages() {
    return this._memoizer.runOnce(() async {
      return await MyStorage().getDownloadUrl(widget.guestbook.imagePath);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      semanticContainer: true,
      clipBehavior: Clip.antiAliasWithSaveLayer,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10.0),
      ),
      elevation: 2,
      margin: EdgeInsets.all(5),
      child: FutureBuilder(
          future: _getFeaturedImages(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return GuestbookPlaceholder();
            } else {
              if (snapshot.data != null) {
                return Hero(
                  tag: "to_single_guestbook_" + widget.guestbook.entryCode,
                  child: Container(
                    width: Get.width / 1.7,
                    height: Get.height / 3.5,
                    child: Image.network(
                      snapshot.data,
                      fit: BoxFit.cover,
                    ),
                  ),
                );
              } else {
                return Hero(
                    tag: "to_single_guestbook_" + widget.guestbook.entryCode,
                    child: GuestbookPlaceholder());
              }
            }
          }),
    );
  }
}

Attempt 2

class _GuestbookCardImageState extends State<GuestbookCardImage> {
  Future<String> _future;

  @override
  void initState() {
    _future = MyStorage().getDownloadUrl(widget.guestbook.imagePath);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      semanticContainer: true,
      clipBehavior: Clip.antiAliasWithSaveLayer,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10.0),
      ),
      elevation: 2,
      margin: EdgeInsets.all(5),
      child: FutureBuilder(
          future: _future,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return GuestbookPlaceholder();
            } else {
              if (snapshot.data != null) {
                return Hero(
                  tag: "to_single_guestbook_" + widget.guestbook.entryCode,
                  child: Container(
                    width: Get.width / 1.7,
                    height: Get.height / 3.5,
                    child: CachedNetworkImage(
                        imageUrl: snapshot.data, fit: BoxFit.cover),
                  ),
                );
              } else {
                return Hero(
                    tag: "to_single_guestbook_" + widget.guestbook.entryCode,
                    child: GuestbookPlaceholder());
              }
            }
          }),
    );
  }
}

What I expect

I expect that after changing the screen and return to the initial screen my images still appearing without the need of reload. I am using Hero animation for the images. This loading behavior destroys my animation because while loading the image urls it shows a placeholder.

A small video how this looks: (And this happens also if I push to the detail screen and pop back to the initial screen)

enter image description here

What could I do to solve this issue?


Solution

  • I think you need to go higher in the widget tree and preserve the state of your page. you can try this solution. The solution is to use PageView widget to display your screen through the navigation bar, and the PageView allowing you to save the page state easily.