I really need help to understand the nature of Static method - flutter

When a instance function being declare Static, does that mean that it can't return a new instance of another object?
Aren't the purpose of the Static keyword is to save the memory, does that mean when i call the static member, it had to return for me the EXACT object ?
class Provider extends InheritedWidget {
final bloc = Bloc();
bool updateShouldNotify(_) => true;
Provider({Key key, Widget child}) : super(key: key, child: child);
static Bloc of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<Provider>().bloc;
}
}
class SignUp extends StatelessWidget {
#override
Widget build(BuildContext context) {
// This is not the same object
final bloc = Provider.of<Bloc>(context);
}
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
// This is not the same object
final bloc = Provider.of<Bloc>(context);
}

Once function is declared static, that means it is no longer "instance" function, but rather class function.
Declaring function static means that you no longer have access to instance (i.e. this). This is just function aliased by the class it is declared in.
Static function can return anything, including new instances of classes, where it is declared.
Static function will not help you to save memory.
My assumption though (I might be wrong) is that static function is a little bit easier for compiler to compile as it does not take part in polymorphism.

Everything from Alex above is correct.
I just want to point the most important differences you should no:
It is not related to any object, and so it can be called directly from the class.
In Java and maybe other languages polymorphic rules no longer work as expected. For this many people do use the Singleton-Pattern, which itself is based on a static function.
Further reading:
https://en.wikipedia.org/wiki/Static_(keyword)
https://en.wikipedia.org/wiki/Singleton_pattern
https://www.javatpoint.com/static-keyword-in-java
https://www.geeksforgeeks.org/static-methods-vs-instance-methods-java/
In general you should try doing some own research before asking questions here, and so make questions less random ;)

Related

Flutter: Is it ok to use notifier constructor to pass initial value in riverpod?

I have a TaskEditor screen and a TaskEditorController which extends Notifier. State is a Task model. I want to make the default value of TaskEditorController as the Task I get as navigation params from another screen. To achieve that, this is what I am doing. Though this is working fine, I am little concerned over the practice.
class TaskEditorController extends Notifier<Task> {
TaskEditorController(this._initialTask);
final Task _initialTask;
#override
Task build() {
return _initialTask.copyWith();
}
}
final taskEditControllerProvider = NotifierProvider.autoDispose<TaskEditorController, Task>(
(() => throw UnimplementedError()));
And this how I am overriding it.
class TaskEditor extends HookConsumerWidget {
const TaskEditor(this._task);
final Task _task;
#override
Widget build(BuildContext context, WidgetRef ref) {
return ProviderScope(
overrides: [
taskEditControllerProvider
.overrideWith(() => TaskEditorController(_task))
],
This is "alright". There's nothing inherently wrong with doing this.
But this approach is a bit discouraged. Relying on overriding providers within the widget tree is considered as "advanced" and "should be avoided if possible".
Chances are there's a different solution to your problem which does not involve such practice.

Is it possible to have both a stateful widgets and a stateless widget as subtypes of another class?

I recently tried to create an abstract widget, that has then both a stateless and a stateful implementation, which both can be accessed via factory-methods.
Below I added a minimal example of the only real working solution I have figured out that works for my use case, but it leaves me with some things to be desired.
For example with this solution, I have to declare and override every variable in the sub-classes, while I would really like to rely on the fact that they are subtypes and implicitly have those variables.
Has anyone of you ever needed to do a similar thing? Have you worked out a different approach?
For those concerned about as to why I would need this: I wanted to make a singular Button-Class for my App, that then has different implementations for specific styles of buttons (regular button, a 'striped' button, a button that 'loads' as the user scrolls down a page and becomes active once the user reached the end of the page, etc.). That way I could then simply call 'Button.implementation' wherever i needed a specific button, and have all the button-related Code in the same place.
Cheers.
abstract class A {
final int intellect;
A(this.intellect);
factory A.giveMeB(int intellect) {
return _B(intellect);
}
factory A.giveMeC(int intellect) {
return _C(intellect);
}
}
class _B extends StatelessWidget implements A {
#override
final int intellect;
_B(this.intellect);
#override
Widget build(BuildContext context) {
return SizedBox.shrink();
}
}
class _C extends StatefulWidget implements A {
#override
final int intellect;
const _C(this.intellect, {Key key}) : super(key: key);
#override
_CState createState() => _CState();
}
class _CState extends State<_C> {
#override
Widget build(BuildContext context) {
return Container();
}
}

How to use Provider/Consumer when extending a class

To start, I'm new to Flutter, so I am completely open to the possibility that my problem stems from a fundamental misunderstanding, but here is my question:
I am trying to get a good understanding of how to use Provider in conjunction with with the get_it package.
I think I understand how to use the Provider pattern in the standard case, by which I mean creating a unique class with a view and a view_model. Where I seem to have become lost is when I design a custom widget as a base template class and then extend that widget so that it can be tailored for use in a specific class view, I'm not seeing how to connect it to the Provider pattern because the base class doesn't know in advance which view_model it needs to listen to.
Below I will provide short example of what I am doing in the standard case, where things seem to work fine, and then I will show a short example of how I am trying to build the custom widget and extend it...
Here is the sample standard way in which I am using the Provider pattern with get_it, in which everything seems to work just fine:
class MyScreenView extends StatefulWidget{
#override
_ProfileEditScreenViewState createState() => _ProfileEditScreenViewState();
}
class _MyScreenViewState extends State<MyScreenView>{
final MyScreenViewModel model = serviceLocator<MyScreenViewModel>();
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<MyScreenViewModel>(
create: (context) => model,
child: Material(
color: Colors.white,
child: Consumer<MyScreenViewModel>(
builder: (context,model,child) => Text(model.someText),
),
),
);
}
}
class MyScreenViewModel extends ChangeNotifier{
String? _someText;
MyScreenViewModel() {
this._someText= 'Sample Text';
}
String get someText=> _someText;
set someText(String value) {
_someText= value;
notifyListeners();
}
}
Here is an example of how I am trying to build a base class, but am uncertain as to how I go about connecting it to Provider: (The idea here is that the below widget would be part of a more complex widget that would have a view_model where the state for the overall widget would be maintained)
class BaseCheckBoxTile extends StatefulWidget{
bool isChecked;
Function(bool) checkBoxOnChanged;
BaseCheckBoxTile({this.isChecked = false, required this.checkBoxOnChanged});
#override
_BaseCheckBoxTileState createState() => _BaseCheckBoxTileState();
}
class _BaseCheckBoxTileState extends State<BaseCheckBoxTile>{
#override
Widget build(BuildContext context) {
return SizedBox(
child: Checkbox(value: widget.isChecked,onChanged: widget.checkBoxOnChanged,),
);
}
}
class CustomCheckBoxTile extends BaseCheckBoxTile{
bool isChecked;
Function(bool) checkBoxOnChanged;
CustomCheckBoxTile({this.isChecked =false, required this.checkBoxOnChanged})
:super(isChecked: isChecked, checkBoxOnChanged: checkBoxOnChanged);
}
My instinct is to want to put something in my _BaseCheckBoxTileState that gives me access to the larger widget's view_model, like what I do in the first example with:
"MyScreenViewModel model = serviceLocator<MyScreenViewModel>(); "
If I had that, then I could assign the values in my _BaseCheckBoxTileState by referring to the model instead of widget (e.g., model.isChecked instead of widget.isChecked). The model would obviously extend ChangeNotifier, and the view that is making use of the custom widget would wrap the widget in a Consumer. However, the _BaseCheckBoxTileState doesn't know what view_model to listen to.
Would I accomplish this by putting some generic Type or Object in for my View_Model which could be assigned when the class is built? Or am I approaching this in a completely wrong way?

non final field in stateless flutter widget

I have a stateless widget and while writing the code I am using a non-final field in the stateless widget and the ide keeps giving me warning that all the fields in stateless widget should be final
But I don't understand why having a non-final field in stateless widget be a problem.
I think it should be perfectly fine to have non-final field because there could be a field that we don't want to modify later but this field can only be initialized inside the constructor function so, for that you need to use non-final field
example:
class Temp extends StatelessWidget {
final int a;
final int b;
int c;
temp({this.a, this.b}) {
this.c = this.a + this.b;
}
#override
Widget build(BuildContext context) {}
}
In the above widget, I can't make c as final because it is initialized inside the constructor function even though I have no plans to change the c variable in the future.
If having a non-final field in a Stateless widget is not a good Idea then How to handle the above situation.
Note: I cannot use the Constructor() : [initialization] {} because the initialization can involve the function or loops
StatelessWidget class A widget that does not require mutable state, so the class is marked as #immutable, Dart language do the best to fix your errors, so "final" keyword will just warn you about that but will not stop the compiling, you can use your code normally without final keyword if you are sure it will initialized one time and not change again at run-time ..
and this is the main reason to have 2 keywords (final, const) for define constants in Dart language
Both final and const prevent a variable from being reassigned.
const value must be known at compile-time, const birth = "2020/02/09". Can't be changed after initialized
final value must be known at run-time, final birth = getBirthFromDB(). Can't be changed after initialized
You can use initialization even for function invocation.
here is an example:-
class SumWidget extends StatelessWidget {
final int sum;
static getSum(List<int> items) {
int perm = 0;
for (var value in items) {
perm += value;
}
return perm;
}
SumWidget(List<int> roles) : this.sum = getSum(roles);
#override
Widget build(BuildContext context) {}
}
but function must be static because The instance member can't be accessed in an initializer.

Controlling State from outside of a StatefulWidget

I'm trying to understand the best practice for controlling a StatefulWidget's state outside of that Widgets State.
I have the following interface defined.
abstract class StartupView {
Stream<String> get onAppSelected;
set showActivity(bool activity);
set message(String message);
}
I would like to create a StatefulWidget StartupPage that implements this interface. I expect the Widget to do the following:
When a button is pressed it would send an event over the onAppSelected stream. A controller would listen to this event and perform some action ( DB call, service request, etc ).
The controller can call showActivity or set message to have the view show progress with a message.
Because a Stateful Widget does not expose its State as a property, I don't know the best approach for accessing and modifying the State's attributes.
The way I would expect to use this would be something like this:
Widget createStartupPage() {
var page = new StartupPage();
page.onAppSelected.listen((app) {
page.showActivity = true;
//Do some work
page.showActivity = false;
});
}
I've thought about instantiating the Widget by passing in the state I want it to return in createState() but that feels wrong.
Some background on why we have this approach: We currently have a Dart web application. For view-controller separation, testability, and forward-thinking towards Flutter, we decided that we would create an interface for every view in our application. This would allow a WebComponent or a Flutter Widget to implement this interface and leave all of the controller logic the same.
There are multiple ways to interact with other stateful widgets.
1. findAncestorStateOfType
The first and most straightforward is through context.findAncestorStateOfType method.
Usually wrapped in a static method of the Stateful subclass like this :
class MyState extends StatefulWidget {
static of(BuildContext context, {bool root = false}) => root
? context.findRootAncestorStateOfType<_MyStateState>()
: context.findAncestorStateOfType<_MyStateState>();
#override
_MyStateState createState() => _MyStateState();
}
class _MyStateState extends State<MyState> {
#override
Widget build(BuildContext context) {
return Container();
}
}
This is how Navigator works for example.
Pro:
Easiest solution
Con:
Tempted to access State properties or manually call setState
Requires to expose State subclass
Don't use this method when you want to access a variable. As your widget may not reload when that variable change.
2. Listenable, Stream and/or InheritedWidget
Sometimes instead of a method, you may want to access some properties. The thing is, you most likely want your widgets to update whenever that value changes over time.
In this situation, dart offer Stream and Sink. And flutter adds on the top of it InheritedWidget and Listenable such as ValueNotifier. They all do relatively the same thing: subscribing to a value change event when coupled with a StreamBuilder/context.dependOnInheritedWidgetOfExactType/AnimatedBuilder.
This is the go-to solution when you want your State to expose some properties. I won't cover all the possibilities but here's a small example using InheritedWidget :
First, we have an InheritedWidget that expose a count :
class Count extends InheritedWidget {
static of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<Count>();
final int count;
Count({Key key, #required Widget child, #required this.count})
: assert(count != null),
super(key: key, child: child);
#override
bool updateShouldNotify(Count oldWidget) {
return this.count != oldWidget.count;
}
}
Then we have our State that instantiate this InheritedWidget
class _MyStateState extends State<MyState> {
int count = 0;
#override
Widget build(BuildContext context) {
return Count(
count: count,
child: Scaffold(
body: CountBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
count++;
});
},
),
),
);
}
}
Finally, we have our CountBody that fetch this exposed count
class CountBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text(Count.of(context).count.toString()),
);
}
}
Pros:
More performant than findAncestorStateOfType
Stream alternative is dart only (works with web) and is strongly integrated in the language (keywords such as await for or async*)
Automic reload of the children when the value change
Cons:
More boilerplate
Stream can be complicated
3. Notifications
Instead of directly calling methods on State, you can send a Notification from your widget. And make State subscribe to these notifications.
An example of Notification would be :
class MyNotification extends Notification {
final String title;
const MyNotification({this.title});
}
To dispatch the notification simply call dispatch(context) on your notification instance and it will bubble up.
MyNotification(title: "Foo")..dispatch(context)
Note: you need put above line of code inside a class, otherwise no context, can NOT call notification.
Any given widget can listen to notifications dispatched by their children using NotificationListener<T> :
class _MyStateState extends State<MyState> {
#override
Widget build(BuildContext context) {
return NotificationListener<MyNotification>(
onNotification: onTitlePush,
child: Container(),
);
}
bool onTitlePush(MyNotification notification) {
print("New item ${notification.title}");
// true meaning processed, no following notification bubbling.
return true;
}
}
An example would be Scrollable, which can dispatch ScrollNotification including start/end/overscroll. Then used by Scrollbar to know scroll information without having access to ScrollController
Pros:
Cool reactive API. We don't directly do stuff on State. It's State that subscribes to events triggered by its children
More than one widget can subscribe to that same notification
Prevents children from accessing unwanted State properties
Cons:
May not fit your use-case
Requires more boilerplate
You can expose the state's widget with a static method, a few of the flutter examples do it this way and I've started using it as well:
class StartupPage extends StatefulWidget {
static StartupPageState of(BuildContext context) => context.ancestorStateOfType(const TypeMatcher<StartupPageState>());
#override
StartupPageState createState() => new StartupPageState();
}
class StartupPageState extends State<StartupPage> {
...
}
You can then access the state by calling StartupPage.of(context).doSomething();.
The caveat here is that you need to have a BuildContext with that page somewhere in its tree.
There is another common used approach to have access to State's properties/methods:
class StartupPage extends StatefulWidget {
StartupPage({Key key}) : super(key: key);
#override
StartupPageState createState() => StartupPageState();
}
// Make class public!
class StartupPageState extends State<StartupPage> {
int someStateProperty;
void someStateMethod() {}
}
// Somewhere where inside class where `StartupPage` will be used
final startupPageKey = GlobalKey<StartupPageState>();
// Somewhere where the `StartupPage` will be opened
final startupPage = StartupPage(key: startupPageKey);
Navigator.push(context, MaterialPageRoute(builder: (_) => startupPage);
// Somewhere where you need have access to state
startupPageKey.currentState.someStateProperty = 1;
startupPageKey.currentState.someStateMethod();
I do:
class StartupPage extends StatefulWidget {
StartupPageState state;
#override
StartupPageState createState() {
this.state = new StartupPageState();
return this.state;
}
}
class DetectedAnimationState extends State<DetectedAnimation> {
And outside just startupPage.state
While trying to solve a similar problem, I discovered that ancestorStateOfType() and TypeMatcher have been deprecated. Instead, one has to use findAncestorStateOfType(). However as per the documentation, "calling this method is relatively expensive". The documentation for the findAncestorStateOfType() method can be found here.
In any case, to use findAncestorStateOfType(), the following can be implemented (this is a modification of the correct answer using the findAncestorStateOfType() method):
class StartupPage extends StatefulWidget {
static _StartupPageState of(BuildContext context) => context.findAncestorStateOfType<_StartupPageState>();
#override
_StartupPageState createState() => new _StartupPageState();
}
class _StartupPageState extends State<StartupPage> {
...
}
The state can be accessed in the same way as described in the correct answer (using StartupPage.of(context).yourFunction()). I wanted to update the post with the new method.
You can use eventify
This library provide mechanism to register for event notifications with emitter
or publisher and get notified in the event of an event.
You can do something like:
// Import the library
import 'package:eventify/eventify.dart';
final EventEmitter emitter = new EventEmitter();
var controlNumber = 50;
List<Widget> buttonsGenerator() {
final List<Widget> buttons = new List<Widget>();
for (var i = 0; i < controlNumber; i++) {
widgets.add(new MaterialButton(
// Generate 10 Buttons afterwards
onPressed: () {
controlNumber = 10;
emitter.emit("updateButtonsList", null, "");
},
);
}
}
class AState extends State<ofYourWidget> {
#override
Widget build(BuildContext context) {
List<Widget> buttons_list = buttonsGenerator();
emitter.on('updateButtonsList', null, (event, event_context) {
setState(() {
buttons_list = buttonsGenerator();
});
});
}
...
}
I can't think of anything which can't be achieved by event driven programming. You are limitless!
"Freedom cannot be bestowed — it must be achieved."
- Elbert Hubbard
Have you considered lifting the state to the parent widget? It is a common, though less ideal than Redux, way to manage state in React as far as I know, and this repository shows how to apply the concept to a Flutter app.