Flutter What is difference between valueNotifier,changeNotifier,stateNotifier? - flutter

What is difference between valueNotifier,changeNotifier,stateNotifier?

ValueNotifier is a special type of class that extends Changenotifier, which can hold a single value and notifies the widgets which are listening to it whenever its holding value gets change.
ChangeNotifier is a class that provides change notification to its listeners. That means you can subscribe to a class that is extended or mixed in with ChangeNotifier and call its notifyListeners() method when there’s a change in that class. This call will notify the widgets that are subscribed to this class to rebuild.
On the other hand, StateNotifier is an immutable state management solution where the state can be directly changed within the notifier only.

There is an interesting difference between ValueNotifier and StateNotifier. The former uses == to assess whether update is needed, while later uses identical check. This has positive performance implications in favor of the later as long as immutable types are used. See https://github.com/rrousselGit/state_notifier#why-are-listeners-called-when-the-new-state-is--to-the-previous-state
For built-in "value types" and enums they work just the same.
One may be tempted to use ValueNotifier for mutable objects, but this doesn't work well because sub-objects of that object can be changed via mutating methods, and this clearly does not trigger updates.
StateNotifier also has some additional options, such as modifying when the value is actually updated.
Therefore my current recommendation is:
Use ChangeNotifier for mutable types.
Use StateNotifier for immutable types.
Ignore ValueNotifier.
StateNotifier is intended to be used with immutable objects, but there is no mechanism in the language to ensure this is the case. This compiles:
class Mutable {
Object? o;
}
class Mistake extends StateNotifier<Mutable> {
Mistake() : super(Mutable());
}

Related

save current state in Scala

Let's say I have an instance of a class and I want to duplicate and save the current state of the item, is there a way to do it without using the copy() method? If I just save the class instance somewhere in a variable, then its state changes too when the state of the original one changes, but I don't want that to happen.
Does someone have an idea of how I can save the current class instance without it ever being mutated, so that whenever I want to use it again, I want the class instance to be exactly the same as when I saved it?
The best way to make a copy of a case class is to use copy. If that is not acceptable (for whatever reason) then you have to create a new instance of the case class with the same values.
But you only have this problem because you are using a mutable value in a class. It is much, much better to keep data classes immutable so that you know that the values won't change under your feet. If you need to change the values, create a new instance with different values and use that, leaving the original untouched.
It take a while to learn to code in a functional way without mutable values, but it is worth the effort!

Why can't non-nullable fields be initialized in a constructor body in Dart?

Often times I have an instance field that needs to be initialized in a constructor. For example, it might be needed to be calculated based on other instance fields, hence I can't initialize it inline (where declared) or with a constructor initializer list.
But it either has to be nullable, or declared late, if I need to initialize it in constructor. The rationale behind late keyword is that programmer states "I'll initialize this before using, trust me", when it can not be determined by the compiler that initialization will take place before first usage. BUT: this "programmer guarantee" seems A) terrible and B) unnecessary in case of constructors, because it can be determined by compiler whether the field was initialized in a constructor (and constructor itself is obviously guaranteed to execute before any other instance methods).
Obvious downside to using late fields in such scenarios is that nothing enforces them compile-time to be actually initialized during construction (or anywhere, for that matter). Plus, every time the late field is read, a runtime check is inserted to make sure it has been assigned a value - I don't need that when I initialize in constructors.
Therefore, it seems that, technically it should be possible to have non-nullable non-late fields that are initialized within a constructor body (and if they are not - compiler can throw an error).
So what is the rationale of requiring constructor-initialized fields to be either nullable, or declared as late? Is there a technical reason why this limitation is imposed, or is it just a design oversight by the Dart team?
Dart executes constructor bodies inside-out, from base class to derived class. This allows virtual dispatch to occur in the constructor body. The fact that virtual dispatch can occur in the constructor body means that the compiler cannot statically determine what code will be executed by the constructor body, and therefore it cannot deduce what the constructor body might ultimately initialize.
That the constructor body can execute arbitrary code (including callbacks) that might initialize members or that might depend on initialized members makes it even more complicated.
Furthermore, allowing members to be not initialized when the constructor body runs would be error-prone and a source for confusion. For example, with:
class SomeClass {
int member;
SomeClass() {
updateMember(0);
}
void updateMember(int value) {
print(value); // Oops.
member = value;
}
}
With Dart's current design, all instance methods (and their overrides) can be guaranteed that members are initialized when the method is called. If members were allowed to be uninitialized when the constructor body is executed, that would not longer be true, and all instance methods then would need to consider if they might be invoked from the constructor (or from a base class constructor), possibly indirectly from other method calls, and whether accessed members might not be initialized yet.
(I'll grant that that previous point isn't terribly strong since it currently can still happen that a member is initialized to an object that the constructor body must mutate, but typically instance methods receiving an empty List, Map, etc. is less of a problem than receiving uninitialized members. The above situation also could happen with late members, but that's the baggage that comes with choosing to use late.)
Null-safety disallows the possibility of accessing uninitialized non-late variables, but your proposal would make that possible.
Also, because there is a distinction between initializing members via an initializer list and via a constructor body, people are encouraged to use initializer lists when possible.
The point that you are ignoring here is that when you want to pass a variable to a constructor you will definitely initialize it, otherwise you wouldn't be able to use that widget because you have to pass the variables needed to its constructor. so this late or nullable keywords can be used for the values that you are trying to pass to a widget and not in the widget itself that you are passing them to, but before it.

The member 'notifyListeners' can only be used within 'package:flutter/src/foundation/change_notifier.dart' or a test

I am using ChangeNotifier and i change their value and notify like below,
// Declare
ValueNotifier<bool> isDisplay = new ValueNotifier(false);
// Change value
isDisplay.value = false;
isDisplay.notifyListeners();
It's working fine. but it's raise warning like below,
Can we resolve this using proper implementation or other things ?
I was getting these errors too, more specifically, those 2:
The member 'notifyListeners' can only be used within instance members of subclasses of 'package:flutter/src/foundation/change_notifier.dart'.dart(invalid_use_of_protected_member)
The member 'notifyListeners' can only be used within 'package:flutter/src/foundation/change_notifier.dart' or a test.dart(invalid_use_of_visible_for_testing_member)
After a bit of research, I've come to some conclusions and a solution. Thought I should share it with people who encounter this problem.
The problem
What it says actually is quite obvious, “If you wanna call notifyListeners(), you have to do it in a subclass of ChangeNotifier or in a test file”
“But why is that?” Understandably, this was my second question. But before that, a little bit about where the heck that notifyListeners method is coming from
notifyListeners method
If you look at the implementation of ValueNotifier, it extends ChangeNotifier class:
and ChangeNotifier has a notifyListeners() method (which is why, in the first place, we can use this method) but not in a usual way:
It's protected.
#protected annotation in Dart | doc
[#protected annotation] Indicates that the annotated instance member (method, getter, setter, operator, or field) m in a class or mixin C should only be referenced in specific locations.
A reference from within the library in which C is declared is valid. Additionally, a reference from within an instance member in C, or a class that extends, implements, or mixes in C (either directly or indirectly), or a mixin that uses C as a superclass constraint is valid. Additionally, a reference from within an instance member in an extension that applies to C is valid.”
In a more worldly explanation: it can be used in subclasses that directly extends (or mixins) the ChangeNotifier class or in test files. Since you want to use it in your logic code, you have to do the first section in this paragraph: “extend or mixin ChangeNotifier where you want to call notifyListeners method.”
Where to extend (or mixin) the ChangeNotifier class?
You may be tempted to use it in your Stateful or Stateless Widget, and, since Dart is single-inheritance, you'd have to “mixin” the ChangeNotifier class to your class, but you'd be wrong.
1. Why you must not mixin to StatefulWidget
ChangeNotifier class defines its own dispose method. And since the class or mixin that mixins to your class supersedes the previous inherited methods, by looking at the methods of ChangeNotifier, you'll notice the dispose method (which is used to remove the listeners). So, if you mix ChangeNotifier to StatefulWidget, now your dispose would be ChangeNotifier's dispose rather than the State's dispose.
Remember, you have to release the resources used by State class no matter what. Normally, if you do not override the dispose method in your State, the framework does this for you and releases the resources by itself, which is cool; but since you just changed the dispose method's ancestor, framework will not trigger the required dispose method. And that will raise a runtime error.
2. Why you must not mixin to StatelessWidget
And on the StatelessWidget's case, now your widget would have an instance variable _listener that's not final which comes from the mixed ChangeNotifier. So, you couldn't define a const constructor, which is the most important part of a StatelessWidget (talking about widget rebuild and performance-related situations).
What to do?
In the end, a solution to this would be, to create a new class to manipulate value changes and extend or mixin ChangeNotifier to this class. Then you can call notifyListeners() method wherever and whenever you like! (but of course, don't call notifyListeners unless you use complex objects or send the same value)
Also, these classes are preferably called as 'Controller', 'ViewModel', 'BLoC', or any other name to state that they're mutating/controlling your values and trigger UI to rebuild when needed. (Which what you should do in the first place: separate your UI from your Logic layer).
Further readings
State management for minimalists
You do not need to call notifyListeners, as this is automatically called when a new value is set.
ChangeNotifier implementations like ValueListener should never require notifyListeners to be called manually.

Is state the same thing as class variables and their values?

I'm struggling to understand the concept of state in Flutter. I'm coming from languages like Delphi, Python, and C#, and thinking:
everything is a widget in Flutter is the same as everything is an object (class instance) in other languages
a widget is an object inheriting from a class with a build method, analogous to classes with OnPaint or OnShow methods in other languages
object properties (member variables) make up a widget/object's state. If there are no member variables or they are all declared as const or final, then the widget is stateless. If not then the properties and their values make up the widget/object's state.
What am I missing? What makes up state beside variables?
PS I get further confused when I read about Flutter elements and element trees, though I may understand better once I've got a handle on widget state.
object properties (member variables) make up a widget/object's state. If there are no member variables or theys are all declared as const or final, then the widget is stateless. If not then the properties and their values make up the widget/object's state.
This point is incorrect. Widgets are always immutable, but a StatefulWidget contains a reference to a State instance. States are where your mutable data is held. They have a much longer life than a typical widget, and include special state management methods such as initState(), setState(). They also have a build() method like widgets and for the most part seem like a widget, but they are actually a State<Widget>.
Should you use a StatelessWidget or a StatefulWidget? This question comes up a lot when starting Flutter development. My rule of thumb is that unless you know you really need a StatefulWidget, start with a stateless one. The reason being they are simpler and the most popular IDEs can convert a StatelessWidget to a StatefulWidget (and produce the corresponding State-extending class).

Should you use "extends" or "with" keyword for ChangeNotifier? - Flutter

I have seen several examples of a model extending ChangeNotifier using both 'extends' and 'with' keywords. I am not sure what the difference is.
class myModel extends ChangeNotifier {...}
class myModel with ChangeNotifier {...}
What is the difference between those two? Which one should I use?
You can use either extends (to inherit) or with (as a mixin). Both ways give you access to the notifyListeners() method in ChangeNotifier.
Inheritance
Extending ChangeNotifier means that ChangeNotifier is the super class.
class MyModel extends ChangeNotifier {
String someValue = 'Hello';
void doSomething(String value) {
someValue = value;
notifyListeners();
}
}
If your model class is already extending another class, then you can't extend ChangeNotifier because Dart does not allow multiple inheritance. In this case you must use a mixin.
Mixin
A mixin allows you to use the concrete methods of the mixin class (ie, notifyListeners()).
class MyModel with ChangeNotifier {
String someValue = 'Hello';
void doSomething(String value) {
someValue = value;
notifyListeners();
}
}
So even if your model already extends from another class, you can still "mix in" ChangeNotifier.
class MyModel extends SomeOtherClass with ChangeNotifier {
String someValue = 'Hello';
void doSomething(String value) {
someValue = value;
notifyListeners();
}
}
Here are some good reads about mixins:
Dart: What are mixins?
Dart for Flutter : Mixins in Dart
extends is used to inherit a class
with is used to use class as a mixin
Refer here to understand difference between mixin and inheritence: https://stackoverflow.com/a/860312/10471480
Refering to ChangeNotifier, the docs says
A class that can be extended or mixed in that provides a change notification API using VoidCallback for notifications.
Hence you can inherit it as well as use it as a mixin
I think this has to do with legacy support. The mixin keyword was introduced in Dart 2.1.0. According to the documentation, you should AVOID mixing in a type that isn’t intended to be a mixin:
For compatibility reasons, Dart still allows you to mix in classes
that aren’t defined using mixin. But, that’s risky. If the author of
the class doesn’t intend the class to be used as a mixin, they might
change the class in a way that breaks the mixin restrictions. For
example, if they add a constructor, your class will break.
If the class doesn’t have a doc comment or an obvious name like
IterableMixin, assume you cannot mix in the class if it isn’t declared
using mixin.
As Dart does not allow multiple inheritances the ChangeNotifier API allows it to be mixed in. As the documentation states:
A class that can be extended or mixed in that provides a change
notification API using VoidCallback for notifications.
IMHO to be aligned to the language specification Flutter should change the ChangeNotifier, separating those reusable implementations into Mixin Classes. At least the Dart documentation makes me think this is something that could not be supported anymore in a future release [the mix in of a non mixin class].
There are lot of discussions around this:
Make ChangeNotifier a mixin
Allow mixins in "extends" clauses
in Provider, Both allow to use notifyListeners(),But
Extend means that (ChangeNotifier) is superclass,
Mixin allows using the methods from (ChangeNotifier) class
also
You can extend one class
But can mixin more than one class
This is a good short article about difference:
Should use Extends or Mixin | Flutter Tips