Is it possible to create enum singletons in Dart? - flutter

Is it possible to create enum-based singletons in Dart, as in Java?

With Dart 2.17 we have enhanced enums supporting instance fields and methods with functionality.
Below is a simple example, and check this DartPad Link to test it yourself.
enum EnumSingleton {
_instance;
static EnumSingleton getInstance() => _instance;
final String name = "Enum Singleton";
void speak() => print('I am an $name');
}

Related

How can we use service locator in custom flutter library or package?

I want to split my app into features and each feature in a package, so how can we apply dependency injection using get_it in each package individually
"each package represent a feature containing all business logic and ui for that feature"
Create a new Interface as a contract for the methods you are going to use from this package.
Then, implement this interface in a new class and wrap the package inside this class with the implementation of the package.
Finally, use your service locator with this class in the same way that you always doing with your normal classes.
Ex.
abstract class Encryptor{
Future<String> encrypt(String input);
Future<String> decrypt(String input);
}
class EncryptorImpl implement Encryptor{
Future<String> encrypt(String input){
final result = await encrypt.encrypt("myKey", input);
return result;
}
Future<String> decrypt(String input){
//same!!
.
.
}
}

what is wrong here? (_instance' has not been initialized)

How I can initialize _instance?
I get "Field '_instance' has not been initialized"
Or any other ways to get rid of nullSafety,,,
here is the code:
class ShoppingBasketData{
static late ShoppingBasketData _instance ;
late List<product> _basketItem;
ShoppingBasketData(){
_basketItem =<product>[];
}
List<product> get basketItem => _basketItem;
set basketItem(List<product> value) {
_basketItem = value;
}
static ShoppingBasketData getInstance(){
if (_instance == null){
_instance = ShoppingBasketData();
}
return _instance;
}
}
What is wrong is that you declared _instance to be late. What that means is that you as a developer promise to initialize it before you access it. If you break that promise, you get an exception.
It seems that you want null to be a valid value, so what you need to do is make it nullable:
static ShoppingBasketData? _instance
You may also want to look into How do you build a Singleton in Dart? so you don't have to reinvent the wheel, and you may want to look into Flutter state management, because singleton is probably the worst of all options.

Common interface for two Flutter plugins

I have two Android specific Flutter plugins. They are for two custom devices to access the same hardware with different platform specific SDKs.
I have successfully implemented both as Flutter plugins. I want use these in Flutter application and use the plugin based on the device.
I have created a common abstract class to expose same API but the flutter plugin class has all static methods which doesn't allows to implement a common interface.
How can we expose a common dart implement from a plugin and use it interchangeably.
For an example let say we have this abstract class as the common interface,
abstract class Pluggable{
void plug();
}
The plugin class which is generated by Flutter create is,
import 'dart:async';
import 'package:flutter/services.dart';
class MyPlugin {
static const MethodChannel _channel = MethodChannel('my_plugin');
static Future<String?> get platformVersion async {
final String? version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
static Future<void> plug() async {
await _channel
.invokeMethod('plug');
}
}
The way of Flutter plugins to have static methods which can not be overridden.
The problem is that your flutter plugin class has abstract methods. There are many ways to do this, from using a proper dependency injection framework to have the right type injected, to using a Provider or other InheritedWidget wrapper to hold the instance of the right plugin class and expose it in a common way.
However, the simplest way is to use a Singleton - assuming that this is something that that gets instantiated right at the beginning of the app running and is used throughout.
The way I'd recommend is to add a static initializer to your singleton. See the example below.
// this declares the abstract class.
abstract class MyAbstractClass {
static void initializeWith(MyAbstractClass instance) {
_instance = instance;
}
// this could introduce a potential bug if you don't initialize
// or try to do it multiple times, so make sure you do that
// properly exactly once.
static late final MyAbstractClass _instance;
static MyAbstractClass get instance => _instance;
// methods to show how this works
void method1();
void method2();
// an example of how to call directly from the class
static void doMethod1() => _instance.method1();
}
// one simple implementation
class MyClass1 implements MyAbstractClass {
#override
void method1() => print(1);
#override
void method2() => print(2);
}
// another simple implementation
class MyClass2 implements MyAbstractClass {
#override
void method1() => print("a");
#override
void method2() => print("b");
}
// and in practice, you simply have to initialize and then
// use however you'd like.
void main() {
// MyAbstractClass.initializeWith(MyClass1());
// MyAbstractClass.doMethod1();
// MyAbstractClass.instance.method2();
MyAbstractClass.initializeWith(MyClass2());
MyAbstractClass.doMethod1();
MyAbstractClass.instance.method2();
}
You'd have to convert all of your static methods to members but that should be as simple as removing any static references and removing the static keywords.

Should I use multiple classes for bloc states or one class with multiple constructors?

I have started learning bloc recently and I noticed some tutorials use multiple classes for states and others just use one class with multiple named constructors.
Example for multiple classes:
abstract class ProductsState {}
class ProductsInitial extends ProductsState {}
class ProductsLoading extends ProductsState {}
class ProductsSuccess extends ProductsState {
final List<Products> products;
ProductsSuccess(this.products);
}
class ProductsError extends ProductsState {
final String error;
ProductsError(this.error);
}
Example for multiple constructors:
enum AuthenticationStates {
initial,
success,
error,
}
class AuthenticationState {
final AuthenticationStates state;
final Authentication model;
final String msg;
const AuthenticationState._(
{this.state = AuthenticationStates.initial,
this.model,
this.msg = ''});
const AuthenticationState.initial() : this._();
const AuthenticationState.success(Authentication mdl)
: this._(model: mdl, state: AuthenticationStates.success);
const AuthenticationState.error(String m)
: this._(state: AuthenticationStates.error, msg: m);
}
Which one is better to use?
In my projects, I use the first way since different state types are clear, you can later build your UI based on that e.g. if (state is ProductsLoading) { show loader }.
You can also generate such classes by using the freezed package (https://pub.dev/packages/freezed). When using it, you would define a single class with different factory constructors (similar to your second option), but the generated code would support the first option you've defined, e.g.:
#freezed
class Union with _$Union {
const factory Union(int value) = Data;
const factory Union.loading() = Loading;
const factory Union.error([String message]) = ErrorDetails;
}
Later, in the UI layer, you could use helper methods like map/maybeMap/when/maybeWhen to build the corresponding view based on state, e.g.:
var union = Union(42);
print(
union.when(
(int value) => 'Data $data',
loading: () => 'loading',
error: (String? message) => 'Error: $message',
),
); // Data 42
I was asking myself the same question.
"The moment you check the concrete type of an instance in your logic, know you're not using polymorphism correctly." - Back in the university.
In the documentation of BloC they use one class with enum in all examples(or extra status class),
the enum will be composed of something similar to SUCCESS FAILURE etc.
Check the PostState mentioned in BloC documentation as example:
https://bloclibrary.dev/#/flutterinfinitelisttutorial?id=post-states
Nevertheless, the multiple sub-classes for state is a commonly used practice among flutter devs. It looks wrong for me, but who knows...

using Equatable class with flutter_bloc

Why do we need to use the Equatable class with flutter_bloc? Also, what do we use the props for? Below is sample code for making a state using the bloc pattern in Flutter.
abstract class LoginStates extends Equatable{}
class LoginInitialState extends LoginStates{
#override
List<Object> get props => [];
}
For comparison of data, we required Equatable. it overrides == and hashCode internally, which saves a lot of boilerplate code. In Bloc, we have to extend Equatable to States and Events classes to use this functionality.
abstract class LoginStates extends Equatable{}
So, that means LoginStates will not make duplicate calls and will not going to rebuild the widget if the same state occurs.
Define State:
class LoginInitialState extends LoginStates {}
Define State with props:
props declared when we want State to be compared against the values which declared inside props List
class LoginData extends LoginStates {
final bool status;
final String userName;
const LoginData({this.status, this.userName});
#override
List<Object> get props => [this.status, this.userName];
}
If we remove the username from the list and keep a list like [this.status], then State will only consider the status field, avoiding the username field. That is why we used props for handling State changes.
Bloc Stream Usage:
As we extending State with Equatable that makes a comparison of old state data with new state data. As an example let's look at the below example here LoginData will build a widget only once, which will avoid the second call as it is duplicated.
#override
Stream<LoginStates> mapEventToState(MyEvent event) async* {
yield LoginData(true, 'Hello User');
yield LoginData(true, 'Hello User'); // This will be avoided
}
Detail Blog: https://medium.com/flutterworld/flutter-equatable-its-use-inside-bloc-7d14f3b5479b
We are using the Equatable package so that we can compare instances of classes without having to manually override "==" and hashCode.
Equatable class allows us to compare two object for equality.
This is the equatable example. Let's say we have the following class:
class Person {
final String name;
const Person(this.name);
}
We can create instances of Person like so:
void main() {
final Person bob = Person("Bob");
}
Later if we try to compare two instances of Person either in our production code or in our tests we will run into a problem.
print(bob == Person("Bob")); // false
In order to be able to compare two instances of Person we need to change our class to override == and hashCode like so:
class Person {
final String name;
const Person(this.name);
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Person &&
runtimeType == other.runtimeType &&
name == other.name;
#override
int get hashCode => name.hashCode;
}
Now if we run the following code again:
print(bob == Person("Bob")); // true
it will be able to compare different instances of Person.
So you don't have to waste your time writing lots of boilerplate code when overrides "==" and hashCode.
Use Equatable like
class Person extends Equatable
In bloc case; if you try to use bloc with mutable state you will face with problems without Equatable. It makes resources immutable reduce performance. It’s more expensive to create copies than to mutate a property.
If it is not clear to you that I tried to explain, reading this could help you.
Equatable overrides == and hashCode for you so you don't have to waste your time writing lots of boilerplate code.
There are other packages that will actually generate the boilerplate for you; however, you still have to run the code generation step which is not ideal.
With Equatable there is no code generation needed and we can focus more on writing amazing applications and less on mundane tasks.
and the props is a getter of equatable that takes the properties that we want to
although it needs no focus on it i only putted properties to props getter
it is not that Important but i suggest you to read more about it in here