Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pages on Navigator stack rebuild when a new page is pushed #11655

Closed
cornelius-tan opened this issue Aug 17, 2017 · 126 comments
Closed

Pages on Navigator stack rebuild when a new page is pushed #11655

cornelius-tan opened this issue Aug 17, 2017 · 126 comments
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels.

Comments

@cornelius-tan
Copy link

Steps to Reproduce

Pages on Navigator stack rebuild when a new page is pushed onto the stack.
Suppose the pages were numbered numerically, in the order they are pushed onto the stack i.e. page 1 -> page 2 -> page 3. When we push Page 3, previous pages from page 1 to 2 rebuild as evident from the print statements. Is this a bug?

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(id: 1),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.id}) : super(key: key);

  final int id;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    print('Page ${widget.id} built!');
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.id.toString()),
      ),
      body: new Center(
        child: new RaisedButton(
          child: new Text('Open next page'),
          onPressed: () {
            Navigator.of(context).push(
              new MaterialPageRoute(
                builder: (_) => new MyHomePage(id: widget.id + 1),
                maintainState: true
              )
            );
          }
        )
      ),
    );
  }
}

Logs

When page 2 is pushed, the log outputs

I/flutter (21176): Page 2 built!
I/flutter (21176): Page 2 built!
I/flutter (21176): Page 1 built!

Expected:

I/flutter (21176): Page 2 built!  // only 

When page 3 is pushed, the log outputs

I/flutter (21176): Page 2 built!
I/flutter (21176): Page 3 built!
I/flutter (21176): Page 3 built!
I/flutter (21176): Page 2 built!
I/flutter (21176): Page 1 built!

Expected:

I/flutter (21176): Page 3 built!  // only 

Flutter Doctor

[√] Flutter (on Microsoft Windows [Version 10.0.15063], locale en-US, channel master)
    • Flutter at C:\Users\tzm\Downloads\flutter_sdk
    • Framework revision b156a0f054 (5 days ago), 2017-08-11 22:01:40 -0700
    • Engine revision fef7d827d6
    • Tools Dart version 1.25.0-dev.9.0

[√] Android toolchain - develop for Android devices (Android SDK 25.0.3)
    • Android SDK at C:\Users\tzm\AppData\Local\Android\sdk
    • Platform android-26, build-tools 25.0.3
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_112-release-b06)
@kerego
Copy link

kerego commented Nov 30, 2017

I have noticed this behavior but couldn't figure out what is the problem, can someone from the team comment on this?

@Hixie
Copy link
Contributor

Hixie commented Nov 30, 2017

This is working as intended. In general, you should assume that all widgets can rebuild at any time, that they don't is mostly just an optimisation.

In particular, routes will rebuild because their navigator state has changed so they might need to update how they draw back buttons and the like.

@Hixie Hixie added the f: routes Navigator, Router, and related APIs. label Mar 8, 2018
@lidroider
Copy link

@Hixie
I have same issue with @cornelius-tan
I understand that when navigator state has changed, routes will rebuild
But I follow the document of MaterialPageRoute, I found out maintainState = true to keep state of previous route.
So what is the "actual" meaning of maintainState and what is the state in maintainState?
Please give me your opinion
p/s: sorry for my English

@Hixie
Copy link
Contributor

Hixie commented Jul 13, 2018

maintainState controls whether the route's widgets and render objects are kept around or not. If you set it to false on a route, then when another route is pushed on top, the entire subtree is thrown away until that route is popped.

@zoechi zoechi added the framework flutter/packages/flutter repository. See also f: labels. label Jul 22, 2018
@lidroider
Copy link

@Hixie
Is there any way to prevent rebuild a widget when another route is pushed on top?
Ex: I have route /a -> Widget A, /b -> Widget B. When I push route /b on /a, Widget A is rebuilt and Widget B is built; when i pop /b, Widget A is rebuilt again.
I expect Widget A not to be rebuilt when i push and pop /b
Please help me
Thks

@Hixie
Copy link
Contributor

Hixie commented Aug 13, 2018

You should generally assume that every widget will be rebuild every frame, and design your build methods to be idempotent (i.e. running them multiple times should do nothing different than running them once), and fast (so that there's no problem with running them a lot). In practice we run build methods less often than that but you shouldn't rely on that.

@shivamlko
Copy link

shivamlko commented Sep 21, 2018

@Hixie I have FutureBuilder and List to populate in Page 1, when I open Page 2, FutureBuilder runs again and duplicates data, and if I pop Page 2 , then again FutureBuilder runs, hence 3 times duplicate data. i am stuck in this
How to maintain and best way to do not execute any FutureBuilder or StreamBuilder when I call setState()
for now I have to make bool var to stop each widget duplicate data ,I this code of Pagination works but when I call but duplicate when pop from Page 2 or setState() is called

import 'package:flutter/material.dart';
import '../widgets/imageGridItem.dart';
import '../widgets/imageBigGridItem.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import '../utils/constants.dart' as constants;
import '../temp/queries.dart';
import 'package:http/http.dart' as http;
import '../blocs/homebloc.dart';
import 'dart:io';
import 'dart:async';
import 'dart:convert';

class GridListPageState extends State<GridListPage> {
  String endCursorID;
  bool isRefresh = false;
  bool firstTime = true;


  String lastCursor;
  ScrollController controller;
  List listData = new List();

  @override
  void initState() {
    controller = new ScrollController()..addListener(_scrollListener);
    super.initState();
  }

  @override
  void dispose() {
    controller.removeListener(_scrollListener);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    print("build");
    if(firstTime) {
      firstTime=false;
      loadMoreData();
    }
    return StreamBuilder(
        stream: bloc.listData,
        builder: (context, snapshot) {
          print('Future $snapshot ');
          if (snapshot.error != null) {
            return Text(snapshot.error.toString());
          }

      
          isRefresh = false;
          if (snapshot.hasData) {
            print(snapshot.data);
            listData.addAll(snapshot.data);

            return dataBody(context);
          }
          if (snapshot.connectionState == ConnectionState.waiting)
            return loadingView();
        }


        );
  }

  Widget dataBody(BuildContext context2) {
    print('Size ${listData.length}');
    return Container(
        color: constants.backgroundColor,
        child: ListView.builder(
            controller: controller,
            itemCount: listData.length == 0 ? 0 : listData.length,
            itemBuilder: (BuildContext context, int index) {
              print('1244');
          
              return addNewItem(listData[index]);
            }));
  }

  Widget addNewItem(var data) {
    print(data['element']['node']['id']);
    return ImageBigGridItem(data);
  }

  void _scrollListener() {
    print('pagination  ');
    if (controller.position.extentAfter < 200) {
    
      if (!isRefresh) {
      
        print('pagin $lastCursor');
        isRefresh = true;
        loadMoreData().then((list) {
       
          setState(() {
            isRefresh = false;
       
          });
        });
      }
    }
  }

  Widget loadingView() {
    return Center(
        child: CircularProgressIndicator(
      backgroundColor: Colors.green,
    ));
  }

 
  Future<List> loadMoreData() async {
    isRefresh = true;


    String body;
    body = json.encode({"query": "{tagview(cursor: $lastCursor)}"});
    print("Outside  $lastCursor $body");

    var url = Uri.parse(
        'https://ueeu1geb42.execute-api.ap-northeast-1.amazonaws.com/staging');
    http.Response response = await http.post(url,
        headers: {
          HttpHeaders.AUTHORIZATION: "Bearer ${constants.apiToken}",
          HttpHeaders.CONTENT_TYPE: "application/json"
        },
        body: body);

    if (response.statusCode == 200) {
      Map data = json.decode(response.body);
      print('JSON $data');
   
      List list = data['data']['tagview']['edges'];
      lastCursor = data['data']['tagview']['pageInfo']['endCursor'];
      print('###$list');
      lastCursor = "\"$lastCursor\"";
      print('End Cursor $lastCursor');
      bloc.addtoList(data['data']['tagview']['edges']);
      bloc.listen();
     
    }
 
  }

 
}

class GridListPage extends StatefulWidget {
  GridListPage() : super();

  @override
  GridListPageState createState() => new GridListPageState();
}

@zoechi
Copy link
Contributor

zoechi commented Sep 24, 2018

@shivamlko you'll need to restructure your code so that the data is not fetched again. For example you can cache it and only fetch from the server if the cached value is null

@and1990
Copy link

and1990 commented Jan 13, 2019

wow. The way widget builds is too complicated for the programmer.

@rrousselGit
Copy link
Contributor

I'll reference it here because this is a very common question:

This is intended. If this causes any problem for you, then you're likely using widgets incorrectly.

You may want to read https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build, which showcase one of the common pitfall and how to solve it.

@cosinus84
Copy link

Because of this behaviour when you want to show the status bar when you push A->B: the status bar appears and dissapears again because widget A is rebuild again after widget B build. Widget A hides the status bar, and B has the status bar.

@Afsar-Pasha
Copy link

Any progress?

@jonmaciel
Copy link

It's still happening and resending API requests of every stacked page for every pushed page... 😱

@jagrdev
Copy link

jagrdev commented Jun 12, 2019

I use stateless widgets for navigation pages where it is posible, because they are not rebuilding or recreating during navigation push or pop and using BlocBuilder for managing their states.

@ghost
Copy link

ghost commented Jun 17, 2019

So the argument is that 'a widget can rebuild at any time' - I think that's a very lazy blanket answer. Sure, a widget COULD rebuild at any time, but that doesn't mean it SHOULD.

A widget SHOULD need to automatically rebuild ONLY when there's a state change, or a change to one of the children's widget. When Pushing a new page, the previous page is intended not to be used, so what is the possible use case of rebuilding an entire page that isn't currently displaying?

Also, the less build calls the more performance the app inherently has (Especially in the case where Google Maps is one of the widgets). So what is the actual need to rebuild a page that has no visual display?

Really, this is something really stupid to deal with. There aren't even any context flags to notify the developer that the page is now in the background.

Edit A stateless widget should not be the accepted answer.

Edit two For anyone arguing that a rebuild does not affect performance, I beg to differ. In the example of a Google Map widget, the entire widget is built and re-rendered leading to more memory taken. Sure, the GC cleans up, but that clean up is not immediate, such is in the case below (All I did was push a blank route and back a few times)
image

@rayliverified
Copy link

I've been following this thread and I've recently come around to @rrousselGit's point of view that all pages should be architectured to be rebuilt at anytime. However, Flutter team should acknowledge that rebuilding multiple pages in the background (i.e. heavy pages with ListViews) is not good for performance. In additional, some guidance on where to place StreamBuilders would be much appreciated.

The reason I've changed my perspective is because I realized that I was looking at this problem through an imperative programming lens. Under the imperative paradigm I'm used to, navigating away from a page (Activity/Fragment) pauses the page and stops most activity on that page. Then, when the page is resumed, resume operations are called and the page is restored. With the Reactive approach, there is no need for pause/resume operations because the page updates to match the state immediately. That's the paradigm shift that changed my perspective.

Take for example a list of articles in a feed. You click on an article to open the reader view. You read the article, add a few claps, and bookmark it to your collection. When you return to the feed, the article item updates to indicate that it's been read and you've clapped/bookmarked it. Under the imperative approach, the feed item is updated when the feed view is resumed and an "updated changed" method is called. Whereas under the reactive approach, the feed item updates the moment the article is read, clapped, or bookmarked. All changes are immediately applied on the article view before returning to the feed view.

All that said, the original issue highlights a very real problem with persisting temporary/local state. Imagine a page with a text input field. The user navigates to another page and the text input field page rebuilds, losing the input text. The text should not necessarily be saved to storage but it should not be lost on rebuild either.

There's definitely workarounds for a lot of the issues here and it's not as bad as I originally thought. Thank you Flutter team for working with us developers and listening to our feedback! 🥰

@Hixie
Copy link
Contributor

Hixie commented Nov 12, 2019

@jonataslaw Please reconsider how you are interacting in this repository. If you are unable to post something friendly and helpful, do not post at all. Thanks. See https://github.com/flutter/flutter/blob/master/CODE_OF_CONDUCT.md for details of our code of conduct.

This bug remains open because we do want to reduce the number of times widgets rebuild around the navigator, however, it will never become nothing. For example, any route with an AppBar and a back button will rebuild any time the app navigates because the back button needs to rebuild to verify whether or not it should be showing a back button or a drawer button.

If you have 100 simultaneously open routes, then you should consider rearchitecting your app to have fewer simultaneously open routes. Fundamentally there is no way that that will be efficient regardless of whether we reduce the number of rebuilds.

If you have an imperative operation, such as showing or hiding the status bar, that happens during build, then I would recommend reconsidering how that is implemented to be more similar to how we do status bar colorisation (for example), where you decide, after the build/layout phase, whether to show or hide the status bar only once.

@jonataslaw
Copy link

@jonataslaw Please reconsider how you are interacting in this repository. If you are unable to post something friendly and helpful, do not post at all. Thanks. See https://github.com/flutter/flutter/blob/master/CODE_OF_CONDUCT.md for details of our code of conduct.

This bug remains open because we do want to reduce the number of times widgets rebuild around the navigator, however, it will never become nothing. For example, any route with an AppBar and a back button will rebuild any time the app navigates because the back button needs to rebuild to verify whether or not it should be showing a back button or a drawer button.

If you have 100 simultaneously open routes, then you should consider rearchitecting your app to have fewer simultaneously open routes. Fundamentally there is no way that that will be efficient regardless of whether we reduce the number of rebuilds.

If you have an imperative operation, such as showing or hiding the status bar, that happens during build, then I would recommend reconsidering how that is implemented to be more similar to how we do status bar colorisation (for example), where you decide, after the build/layout phase, whether to show or hide the status bar only once.

Hixie, I'm not talking about 100 routes at once. Often 10 routes (3 of them with listview and heavy widgets) are enough to crash an app.
This is not difficult to reproduce. Just take the video_player example and put it in a listView, and duplicate it in Screens.
To say to change the approach of the application, is to respond that with Flutter you can not create applications such as Facebook, Spotify, and other applications of infinite routes (which have no logical limitation).
I added a pull that changes the opaque from false to true, but after your answer, I see that perhaps instead of changing that which will have side effects, it might be more interesting to set this to MaterialPageRoute and CupertinoPageRoute. This would solve the problem of 80% of issues related to a single boolean.
The current solution is to create a PageRouteBuilder because it lets you pass opaque = false to boolean.
I suggest you can do the same with MaterialPageRoute and CupertinoPageRoute, so it is easy for you to choose between having rebuilt routes or not, even if choosing does not have the side effect of always displaying the back button.

@cosinus84
Copy link

@Hixie I think there should be some best practices documentation regarding Navigation. Anyone that starts with Flutter should understand this aspect of flutter navigation.

Somehow if you look over the internet(questions over questions) you find that flutter had issues in explaining to new developers how the state should work in real applications. It wouldn't be fair for navigation which is a strong pilon of an app to share the same fate. The basic example of the issue needs some explanation and documentation from flutter team (https://flutter.dev/docs/development/ui/navigation)

@jonataslaw
Copy link

Hi Guys, I made a pull request that allows you to set a parameter that ends the reconstruction of previous screens.

#44731

I made observations as to what Hixie said regarding this could cause side effect regarding the display of the back button or the drawer, however I did not get any problem with this in my tests.
This pull changes 2 files (material / page.dart and cupertino / route.dart), and using the navigation code below there is no rebuild of previous screens.

Navigator.push(
context,
MaterialPageRoute(
opaque: false, builder: (BuildContext context) => NextScreen()));

I wanted to use "rebuildRoutes = false" instead of "opaque = false", but I think this may cause confusion in the code by not making explicit what prevents rebuilding.

I am happy with the practical results. I've been testing this for over 12 hours in gigantic apps, and the route animation that used to freeze on low end devices is butter-smooth due to the CPU spike caused by rebuilding over 100 widgets at once (on previous routes) .
I apologize to Remi if I was rude, my intention was not to disrespect anyone or to be rude, but only to come up with a solution to a problem that has been open for 2 years, and today, with the problem solved (for me, because if if there is any objection to pull I will continue to use it because that solves my problems). I could see that maybe I got a little impolite in my comments.
I just want to contribute to this project that made me abandon RN once and migrate applications with millions of users to Flutter <3

Well, that's all for today.
Bests.

@ghost
Copy link

ghost commented Nov 14, 2019

Regardless of personal squabbles, this has been an issue which has been - in many accounts - squashed by many opinions and insights relating to different facets of the framework.

Thank you for your workaround @jonataslaw - it definitely needs to go through a review process, but I really hope that's the solution we've all been looking for. It's great to see the development progress still continuing regardless of personal opinion.

@AlastorReach
Copy link

Hello everybody, I am glad to see the code posted few day ago worked for somebody. I am a newby in Flutter and it's interesting the variety of opinions about the advantages or disadvantages of using opaque = false. But, as I said previously, it worked for me. I am glad to know that the code worked for others.

@jonataslaw
Copy link

jonataslaw commented Nov 14, 2019

While pull is not analysed, you can test the solution on my lib of routes.
https://pub.dev/packages/get

I created it to reduce the boilerplate and have a web-friendly syntax, just "Get.to(NextPage());" is enough to navigate to a next route (No need context too)
and well, with it there is no route reconstruction, because I changed how things work in your routing.
I would like to see this fixed in the framework, so I did the pull, but anyway, I will use this lib, because it reduces 3 lines of code to call a new route, and that sounds cool.
I thank all all the devs who commented here, from AlastorReach who posted the workaround to those who demonstrated when the bug occurs, and I apologize once again if I was rude to anyone, as it was definitely not my intention.

@BobErgot
Copy link

The solution mentioned by @AlastorReach helped me solve the following issue.

I have two Pages: Page1 and Page2.

Page1 has three BottomTabs: TabA, TabB and TabC.

TabB navigates to Page2 and on return to Page1 it resets to default tabA instead of maintaining TabB.

Based on the log I figured that this issue was caused because Page1 was rebuilt every time Navigator.push was used and hence restricting the rebuilt solved the problem.

But as @rrousselGit mentioned this is not an optimal solution. Hence looking out for alternatives to this. @Hixie

@RuedigerMoeller
Copy link

RuedigerMoeller commented Nov 28, 2019

Navigator would be more useful if there was a hook enabling me to handle route changes e.g. sometimes just setting state on the current page widget. The assumption that a full page switch should happen with each route change is too strong. Think of a search with list result and i want to display previous search result on pop() keeping the same widgets and state. Similar to webapps where the route history management is completely separate from the webapp's handling of a route change

@Hixie
Copy link
Contributor

Hixie commented Nov 29, 2019

This bug has gotten way out of hand and people are reporting lots of unrelated different issues here.

The original issue that was reported is working as intended so I'm going to close this issue.

I encourage you to all file your own separate issues so that we can investigate your specific cases individually. File a bug, make sure to include precise steps to reproduce including full code, explain what the behaviour you're seeing is and what the behaviour you expect is (and why).

@Hixie Hixie closed this as completed Nov 29, 2019
@rrousselGit
Copy link
Contributor

On a related note @Hixie, do you think it'd be feasible to have a "true" fix to this rebuild by changing Overlay's _Theatre call from:

_Theatre(
  onstage: Stack(
    fit: StackFit.expand,
    children: onstageChildren.reversed.toList(growable: false),
  ),
  offstage: offstageChildren,
);

to:

_Theatre(
  onstage: onstageChildren.reversed.toList(growable: false),
  offstage: offstageChildren,
);

where the previous Stack would be implemented manually by TheatreRender instead of using composition?

From my understanding, it is the reparenting from onstage to offstage that is the original problem this issue was about.

If that's a reasonable fix, I might give it a try and implement it myself.

@Hixie
Copy link
Contributor

Hixie commented Nov 29, 2019

Please file a new bug to discuss specific proposals.

@TreeLiked
Copy link

How do I solve this problem? There are many images on my homepage. When I navigate to a new page or return, the images are reloaded, causing the page to flicker.

@cuong1112035
Copy link

How do I solve this problem? There are many images on my homepage. When I navigate to a new page or return, the images are reloaded, causing the page to flicker.

You can use const to to create your images. They should not reload when their parent reload

@TreeLiked
Copy link

@cuong1112035 Oh, however, the const constructor requires constants during compilation. The picture here is a network picture, which is a link requested from the server. I cannot use the const constructor.

@cuong1112035
Copy link

cuong1112035 commented Dec 8, 2019

@cuong1112035 Oh, however, the const constructor requires constants during compilation. The picture here is a network picture, which is a link requested from the server. I cannot use the const constructor.

you could try AsyncMemoizer to load your remote images just one time. Or maybe just wrap your remote image within a const widget. Hope this help

@TreeLiked
Copy link

@cuong1112035 Sorry, can you give me an example about using the image const constructor? I have been delaying this issue for a long time, thank you very much~ I am using CachedNetWorkImage

@tony123S
Copy link

tony123S commented Dec 8, 2019

@TreeLiked Are you using bloc?

@TreeLiked
Copy link

TreeLiked commented Dec 8, 2019

@TreeLiked Are you using bloc?
No, the homepage like the picture 'here', the image container is cachednetworkimage , when i push a new route, this page rebuild and rebuild when route pop, the images will rebuild and page flicker not smooth, is there a good solution for this , thanks~

@cuong1112035
Copy link

@cuong1112035 Sorry, can you give me an example about using the image const constructor? I have been delaying this issue for a long time, thank you very much~ I am using CachedNetWorkImage

"const constructor requires constants during compilation" you are right. I just check it and there are no ways to use const to prevent your image widget to rebuild.
Also, CachedNetWorkImage caches your images already so that you don't need to use AsyncMemoizer for caching.
Sorry for my stupid suggestion, hope this issue will be resolved in next Flutter versions

@TreeLiked
Copy link

@cuong1112035 Sorry, can you give me an example about using the image const constructor? I have been delaying this issue for a long time, thank you very much~ I am using CachedNetWorkImage

"const constructor requires constants during compilation" you are right. I just check it and there are no ways to use const to prevent your image widget to rebuild.
Also, CachedNetWorkImage caches your images already so that you don't need to use AsyncMemoizer for caching.
Sorry for my stupid suggestion, hope this issue will be resolved in next Flutter versions

oh, yes, thank you still~

@SBDavid
Copy link

SBDavid commented Dec 9, 2019

This is working as intended. In general, you should assume that all widgets can rebuild at any time, that they don't is mostly just an optimisation.

In particular, routes will rebuild because their navigator state has changed so they might need to update how they draw back buttons and the like.

I fix the "rebuild" problem by adding a key to Overlay build function.

First I add a GlobalKey to OverlayEntry class. For example _key2. This key will be used in TickerMode, the purpose is to give a Key to overlay offstage elements.

class OverlayEntry {

  OverlayState _overlay;
  final GlobalKey<_OverlayEntryState> _key = GlobalKey<_OverlayEntryState>();

  final GlobalKey _key2 = GlobalKey();
}

And the next step is add _key2 to build function.

class OverlayState extends State<Overlay> with TickerProviderStateMixin {
@override
  Widget build(BuildContext context) {
    final List<Widget> onstageChildren = <Widget>[];
    final List<Widget> offstageChildren = <Widget>[];
    bool onstage = true;
    print("overlay build");
    for (int i = _entries.length - 1; i >= 0; i -= 1) {

      final OverlayEntry entry = _entries[i];
      if (onstage) {
        print("onstage ${entry._key}");
        onstageChildren.add(_OverlayEntry(entry));
        if (entry.opaque)
          onstage = false;
      } else if (entry.maintainState) {
        offstageChildren.add(TickerMode(key: entry._key2, enabled: false, child: _OverlayEntry(entry)));
        print("offstage ${entry._key}");
      } else {
        print("!maintainState ${entry._key}");
      }
    }
    return _Theatre(
      onstage: Stack(
        fit: StackFit.expand,
        children: onstageChildren.reversed.toList(growable: false),
      ),
      offstage: offstageChildren,
    );
  }

}

And then Flutter diff algorithm will know how to update offstage element properly, other than just inflateWidget. The inflateWidget method will reload images which were used in offstage elements, thus cause serious performance issue.

@Hixie
Copy link
Contributor

Hixie commented Dec 10, 2019

Please file a new bug to discuss specific proposals.

@flutter flutter locked and limited conversation to collaborators Dec 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

No branches or pull requests