How to prevent Stateful Widget stored in List to be disposed? - flutter

Let me start by explaining the problem. I have several buttons which are created based on data I'm getting from a server. On each button click I need to create and display a widget which will present me some data (this widget is also built dynamically). The state of this widget has to be preserved during the lifetime of the app. (for example if I click another button and show a different widget, I need to be able to click on the first button and show the first widget in its preserved state). Number of buttons can also be changed during the app lifetime.
I tried using IndexedStack to achieve this, but when the number of buttons is changed I need to add "pages" to IndexedStack, therefore I need to recreate a new IndexedStack which will have some of my old widgets, so I pull widgets from a List or create new ones if needed. This works great, except Flutter calls dispose() method on my widgets which are stored in the list. I tried using the AutomaticKeepAliveClientMixIn but it didn't help.
I'm guessing this has something to do that the widgets get detached from the parent, but when I reattach them to new parent (new Indexed stack) Flutter doesn't figure out this properly.
Any ideas?

Try to store data to local storage or sqlite for persistence data.

Related

How to not change the state in widget that shared in two differents Tabs

I'm creating an app and I'm using AutoTabs so I can have different widget tree and be able to move between them without losing state from one tree to another.
I have a small problem and it is that when I share the same widget in two trees and change the state of one, using a StateNotifier, it is logically changed also in the other.
For example, I'm on Tab1 on a page that is an article searched and I move to Tab2 and navigate to the page to find an article that is shared,
How can I do so that when changing the state of the searched in Tab1, the state is not modified on the same page but in Tab2? being able to share the max code
if you don't want to lose your state. you can use IndexedStack widget
It sounds like you're using Riverpod to represent local widget state.
Riverpod is about shared state. So the state being shared between widgets is logical
If you don't want that, you can use a normal StatefulWidget, or flutter_hook's HookWidget

Reuse Widget Across Two Pages With Keys

Long-winded context, scroll to bottom for specific question:
I have a page with a custom widget (EntrySearch) containing a ListView and a search bar. When the user clicks on an item in the list view, I push a new page with the same list view and a panel displaying item details. The list view's items are lazily loaded from a Stream backed by an asynchronous query (the stream is paused until the user scrolls to the end of elements fetched so far). The stream is replaced whenever the user types in a new string in the search bar.
I want the widget to have the same list view (elements, scroll position, etc.) and search bar state across both pages.
I could achieve this with any of the many state management solutions suggested on similar questions about shared widget state across pages (eg this one). However, because my ListView is backed by an asynchronous stream along with a ton of other state, this becomes a total pain of caching results fetched so far, creating a new Stream that starts where the old one left off (can't have two StreamBuilders backed by the same non-broadcast stream), etc. etc. I'd really like to avoid such a messy solution.
Giving the top level Widget whose state I want to share a global key is one line (instead of ~50) and results in shared state across the pages. However, when I push the new page, the old page stays in the Widget tree on standby, so I get an error for having two widgets with the same global key in the widget tree at the same time. I can set maintainState to false on the first page, but then when I pop the second the first page shows up as just a black screen.
Is there:
a way to use a global key widget across two pages without them both being in the tree at the same time
a specialized key specifically for reusing a widget across two different pages
some other approach I'm not thinking of?
Here's my widget tree with the two pages. EntrySearch is the widget I want to reuse across the two pages.
If none of the above works, I'll have to use a traditional state management strategy which is going to be at least an order of magnitude more verbose and bug-prone.
Here's the solution I went with, if anyone else is approaching a similar problem:
I couldn't find a way to use keys for this problem. What I'm doing now is I have a single class that contains all the state my custom widget needs to build itself. Whenever I push a route to the navigator, I copy the current page's state object with the desired changes and then add the new state to the RouteSettings.argument field. I can then access the page's state object anywhere within the page using ModalRoute.of(context).settings.arguments.
As expected, this solution was massively complex and painful with a lot of subtle bugs I had to work through. It works and at least has slightly more desirable behavior than simply maintaining identical state across both pages: when I pop a page, the state pops too. This means a user can go back to their previous scroll position in the ListView with the back gesture.

Preserving the State of a Drawer in Flutter

I have a stateful Scaffold widget, where the body contains a list of entities with various properties (e.g. shoes or cars) and Drawer widget, which is empty at first, except for two buttons at the bottom ("Cancel" and "Filter") and a FAB. The user can add various filters with the FAB (e.g. the user can add a shoesize-filter, or a color-filter).
The problem I have is the following: Let's say the user selects various filters and works with them (i.e. ticks checkboxes, enters a shoesize, changes sliders, etc.). When the user is ready to apply the filters, he can click the "Filter" button, which closes the Drawer (onTap -> callback -> Navigator.of(context).pop()). But when the user wants to go back, reopen the Drawer, and adjust one of the filters, it obviously doesn't work, since the widget is being rebuilt from scratch.
Currently, the way the filtering works is, once the "Filter" Button is pressed, all the various values from the added filters are collected into an object FilterPackage, which is then passed via callback to the Scaffold widget, which then applies the values from the FilterPackage to the list of entities.
One solution I came up with, would be feeding this FilterPackage object to the Drawer widget in its constructor, which would provide all the information necessary to rebuild the widget just how it has to be.
Is that a reasonable solution? I have already made some research, but struggled finding a solution on what would clearly be the best and recommended way to preserve the drawer's state. Using PageStorage / PageStorageBucket seems overly complicated for this case. Or am I wrong?
Thanks in advance for any guidance.

Flutter Webview reloads every time I switch screen

I'm making an app with a BottomNavigationBar with 5 different screens, each of them has a web view. The problem is that everytime I come back to a screen that was previously loaded, it reloads. I have tried using AutomaticKeepAliveClient from copy pasting this code but I doesn't seem to work. I'm new with Flutter so be precise please, thank you.
AutomaticKeepAliveClient is mainly used for keeping a child alive in lazily rendered list views. In your case whenever you switch tabs your current page get disposed and new page materializes on top of it, that means each time when you switch tab a new page is created including all it's widgets.
So if you want to keep your previously loaded web views alive, you have to go with either PageView widget or use Stack widget to load your pages programmatically while the user clicks on a tab.
This is a detailed example about implementing your requirement using PageView widget . you can also find an example with Stack widget under that question.

How to load data on a screen on the press of a button without routing and rebuilding whole screen

Pardon me if this is a naive question but I am trying to figure out a way in Flutter to load different data when the user clicks a button. The way I currently see is routing the user to a new screen everytime but I am sure there would be a better approach without loading the whole screen everytime
You should use a Stateful Widget
I would create a Future Builder / ListView Builder. Depending on how you want it to behave you could have the ListView items clear before regenerating the list of items to show.
Future Builder you could create a function to return certain widgets depending on the request you make with the function.