Where should my automatic screen change occur - presentation or model? - flutter

I am using scopedModel approach in flutter, but the question still remains with other patterns like flutter.
-My UI calls authModel.login()
-authModel.login does async work and calls notifyListeners
-build is automatically triggered on my UI
-inside build method, UI checks the login state on authModel, then calls
addPostFrameCallback to change the screen from the build method.
Is this the best design? I feel like this is code smell, but I am not sure. Would it be better if the authModel was passed an onLoginCompleteCallback function from the UI that would change the screen, and then I would not need to call addPostFrameCallback in the build method?
The presentation on the screen is not dependant on the isLoggedIn bool at all. Its just observed to change the screen.

Related

addPostFrameCallback vs scheduleFrameCallback

So, I was wondering, when to use WidgetsBinding.instance.addPostFrameCallback and WidgetsBinding.instance.scheduleFrameCallback for setState, as according to the documentation, the first one doesn't initiate a frame on its own, while if we asynchronously call setState then it might get called during the build of another widget, which can cause not to update the other widget, so for it, we add it as a "post frame" callback, but if it is called not during a build, then it will not initiate the next frame on its own, i.e we cannot always wrap async setState calls with it, as there is a good chance it might be called during not a build, that's when I found scheduleFrameCallback, and according to its documentation, I think it schedules the next frame and adds its as a callback to it, i.e it also initiates a frame. So is it always better to call setState inside it, or is it something else?

where to write logic for every widget in flutter?

I know this is a basic question but I wanna know how you guy's implement logic for your widgets. I normally write logic in build() function just above the return type.
What do you mean by logic..?? If you are talking about like adding some values.. then we use a different method for that outside the build Method because build method will rebuild when the set state method called so some times logic can be used inside the build but some time we need to write the logic in different method and called them..
Build method will rebuild every time the app state got change or refresh
if you talking about widget state
You can write it in separate file using state management approaches like (Getx,Provider)
You can write it in separate function if you need to perform setState that method will update the state
...Try to use separate functions and controllers for logic it will help you in scalability for your code
If you write your logic in build method means it will rebuild every time when the page is refreshed.
I will suggest you to follow MVVM(Model View ViewModel) architecture, so that all the business logics can be written in controllers (ex: cart_controller.dart) .So that your files are separated from actual widgets.
UI goes into - cart_page.dart,
Logic goes into - cart_controller.dart

Changing state of entire page vs one button in flutter

Ok, I am working on a media player app using flutter. Now when I press the play button, it changes to pause button. (Only the icon on the button changes)
The onPressed function for the button changes a boolean value and calls the setState() method.
It goes something like this.
bool _playing = false;
void _onPlayButtonPressed() {
setState () {
if (_playing)
_playing = false;
else
_playing = true;
}
}
I also have a function that returns the icon based on the value of _playing.
Widget _playButtonIcon() {
//This function has no setState() call
if (_playing)
//return pause icon
else
//return play icon
}
Everything works fine. The icon changes everytime I press the button. However as mentioned in docs and also in Flutter Demo App, setState() method calls the build method. Which redraws the entire widget tree including child widgets that are completely unchanged.
Is this approach justified or is this an overkill?
Do I have to put the button on a different Stateful Widget Class and call its build method via setState() everytime I tap this playButton?
What if I have other widgets that also changes the state of UI. Possibly changing different widgets?
What is the proper way to do this without having a performance hit?
Creating a play button that is a widget of its own with a state that maintains whether it is playing or not definitely makes sense. Now when you call setState on the parent widget it does call the build method, but as far as I know it does not necessarily redraw everything from scratch. If no changes are found in some of the embedded widgets it does not redraw them since they are already in the widget tree. Finally, it is okay to call setstate, however if your app starts getting bigger and you find yourself calling set state in too many places, and want to use global keys, I would advise looking into the Provider package, and making use of the ChangeNotifier/Consumer pattern.

Flutter: avoid build() method of previous route being called when navigate to next route

My flutter app is showing a splash screen (statefulWidget) as a first route. This route is showing an animation while, on the background, calling an API to get some data.
Once the data has been received and the animation is complete, it navigates to the second route.
All works fine, except that, when calling the Navigator to navigate to the second route, the second route is shown, but i can see again the response from the API on the first route, that is being called.
It turns out that, when the second route is built, the build method of the previous route is called too, making an unnecessary API call again.
How to avoid this behaviour?, I believe this must be a bug on Flutter??
current flow (non-desired): SplashRoute(build) ---> Navigator ---> HomeRoute(build)+SplashRoute(build)
desired flow: SplashRoute(build) ---> Navigator ---> HomeRoute(build)
What you are trying to do is to work against the framework. It's a futile effort. Instead, you should work with the framework. Here is why and how:
Build methods should not make API requests. Build methods should use fields of your state class to generate a UI without any side effects.
Please move your API calls to the initState method, save their results in fields of your state class with setState and get the build method to use them without generating any side effects.

How should I tell flutter that my app needs rebuilding externally?

I want my app to get an intent, and depending on the intent to display something in the app.
Normally, when a widget depends on state, you put it in a State and run setState().
The issue is that when I try starting my flutter app with different intents, I just get I/FlutterActivityDelegate( 4472): onResume setting current activity to this. And in a way it makes sense - I'm not saying anywhere in the flutter code that my widget needs repainting - since I get my intent through Java.
On the other hand, there should be a way to tell flutter to repaint my widget by intent? Or is there something else I should do?
Specifically to get notified about onResume event you can use WidgetsBindingObserver. Implement its didChangeAppLifecycleState method and respond to AppLifecycleState.resumed by doing whatever it is you want the UI to do, such as call setState to trigger rebuild. That said, there needs to be an effective change for the UI to be repainted. Simply calling setState with no effective state change may not result (in fact, should not) in actual UI changes.
In general, you can send a message from Java (or Objective-C/Swift) to Flutter using BasicMessageChannel and make your app react to the message (e.g. call setState or schedule frames).