What is the best way to define singleton properties in Flutter/Dart? - flutter

I am using flutter_easyLoading package for loaders in my flutter project. It says in the documentation that it creates a singleton and I have to define its properties only once somewhere and it would be available throughout the app. What is the best practice to define these properties?
Right now I am initializing its variables in a splash screen file like this.
class _SplashScreenState extends State<SplashScreen> {
#override
void didChangeDependencies() async {
super.didChangeDependencies();
EasyLoading.instance
..displayDuration = const Duration(milliseconds: 2000)
..indicatorType = EasyLoadingIndicatorType.fadingCircle
..loadingStyle = EasyLoadingStyle.dark;
}
Should I do it this way or maybe define some util method for all these properties.

You can use a factory constructor implement singleton classes in dart.
This is a simple example adapted to this context
class EasyLoadingSingleton {
static final EasyLoadingSingleton _easyloading = EasyLoadingSingleton._internal();
factory EasyLoadingSingleton() {
return _easyloading;
}
EasyLoadingSingleton._internal();
}

Related

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.

Flutter - How to call functions (and variables) between stateful widgets?

I have this function in a widget (homescreen):
void toggleRecording() async {
// HERE IS THE CONFUSION I GUESS
_isRecording = !_isRecording;
recorder = SoundStream(isRecording: _isRecording);
//recorder.toggleRecording(_isRecording);
setState(() {
_isRecording = recorder.isRecording;
});
if (_isRecording) {
startTimer();
_stopwatch.start();
} else {
stopTimer();
_stopwatch.stop();
}
}
It needs to call (trigger) another function in my recorder class:
void toggleRecording() async {
widget.isRecording ////// currently being passed as an argument from homescreen
? {_recorder.stop, await save(_micChunks, 44100)}
: _recorder.start;
}
Also, the boolean variable _isRecording is present in both the classes. How do I sync the state?
In your situation passing reference of function through widgets will work. However best practice of this will be using provider package.
Managing functions from provider will allow you to control functions from all pages.
If you change a variable you can call notifylistener() function inside your provider function. So that you can change state of widget.
I will try to explain it in a glance however this is an important subject of flutter.
Here is my folder structure
At provider folder we define our provider classes.
Firstly i define class which extends changeNotifier class. This is what make this class provider.
Side note: notifyListener() function here calls setState of every widget if you use any variables inside that class and this is what you are searching for.
Then i import it into my main.dart file or whatever file you want. Only condition is being above the widget that you will use provider at.
At last you can use your function at everywhere if you import provider package and define your provider like i did in this code.
At last here is the visualized stucture of provider package.
I wish i explained it well. There is more about it on youtube.
Pass the function to other widget
using Function keyword
Say ContentWidget is your child and ParentWidget is parent
class ParentWidget extends StatefulWidget {
//Do Something
void onSomeFunction()
{
ContentWidget(onTimerUpdate:onTimerClosed)
}
void onTimerClosed()
{
//Perform Operation on Timer Change
}
}
class ContentWidget extends StatefulWidget {
final Function onTimerUpdate;
ContentWidget({
Key key,
#required this.onTimerUpdate,
}) : super(key: key);
void onAnyActionFromChild()
{
widget.onTimerUpdate() //Note () can have any param or can be null
}

How can I access an instance of an object in different classes / pages without a widget tree context?

I am trying to access an instance of an RtcEngine object for AgoraIO from another class/page that doesn't have a widget tree, and therefore no context to refer to with Provider.
First I'm calling initPlatformState() from this class in order to initialize the RtcEngine engine:
class Game extends StatefulWidget {
#override
_GameState createState() => _GameState();
}
class _GameState extends State<Game> implements GameListener {
#override
void initState() {
super.initState();
Agora().initPlatformState(widget.playerId);
}
}
initPlatformState initializes the RtcEngine by creating an instance called engine that I need to use later on to call other methods. This class also contains the method I want to call later using the same instance to adjustVolume...
class Agora {
RtcEngine engine;
// Initialize the agora app
Future<void> initPlatformState(int playerId) async {
RtcEngine engine = await RtcEngine.create(APP_ID);
}
void adjustVolume(int uid, int volume) {
engine.adjustUserPlaybackSignalVolume(uid, volume);
}
}
This is the class that I want to call adjustVolume from. I was considering using Provider to pass the instance to this class but it extends another class and it doesn't have a widget tree with context so I'm not sure how thats possible or if there is a better way.
class Remote extends Component {
final int id;
Remote(this.id);
#override
void update() {
//this is where I'm trying to access the engine instance that was created to call adjustUserPlaybackSignalVolume method
}
}
Any suggestions on how to reuse that instance of "engine" given my situation would be greatly appreciated!

Unable to define object inside a statefulwidget

I am trying to store data in an object reference right now it's just a simple class but letter i am replacing it with a singleton class kindly explain why I am not able to initialize the object just above build method.
class MyStatefulWidget1State extends State<MyStatefulWidget1> {
final TextEditingController titleController = TextEditingController();
Data().value = "dscs"; **//IF i define here it will produce error**
#override
Widget build(BuildContext context) {
Data().value = "dscs"; **// bu if i define here it will work just fine**
return TextField(controller: titleController);
}
}
class Data {
String value;
}
In any type of class we can only create variable and method while you are trying to access objects member variable(value) that't why it is giving error.
While build method is also one type of method, so you can access any class or object member variable too. That's why it is working over there.
If you create simple object Data class in MyStatefulWidget1State state then then try to access it's member variable then also you will get same error.
Something like following.
Data c = Data();
c.value = 'f';
But we can do it in any method, so it will work in build method.
You can use initState() for this purpose.
#override
void initState() {
super.initState();
Data().value = "dscs";
}

How to access it's static constant from instance of an object?

I have an object that has static constant which I need to reach from its instance.
class ChatsScreen extends StatefulWidget {
var arguments;
static const name = ADatas.chatRoute;
ChatsScreen(this.arguments);
createState() => ChatsScreenState();
}
In above class' State object, I want to call static const name. Above class' State object's code:
class ChatsScreenState extends State<ChatsScreen> with RouteHelper{
String userName = "";
var textEditingController = TextEditingController();
#override
void initState() {
getRouteName(widget); //=> as I understand and see on the VSCode, its the ChatsScreen object.
super.initState();
}
}
I'm trying to implement an interface so I don't know the actually class name while writing the interface. And I thought that I can reach its static constant if I know its actual class. And I wrote something like this but it seems not to be possible. I guess I have a misunderstanding.
class RouteHelper{
String getRouteName(dynamic instance){
if(instance is StatefulWidget){
return instance.runtimeType.name; // => !!!
}
}
}
Note: I'm not trying to get the route name in actual. It's just a concept that i used in this question, so please don't refer better way to get the route name in flutter.
You can't do it like that, people have talked about this in this issue.
However you can kinda do it using class members and typing system.
abstract class Routed {
String getClassRoute();
}
class ChatsScreen extends StatefulWidget implements Routed {
var arguments;
static const name = "myexampleroutename";
ChatsScreen(this.arguments);
createState() => ChatsScreenState();
#override
String getClassRoute() {
return ChatsScreen.name;
}
}
class RouteHelper {
String getRouteName(Routed instance) {
return instance.getClassRoute();
}
}
I said you can't, but with dart:mirrors it is possible, however it is banned on Flutter packages. There is reflectable package that tries to fix that using code generation, but I am not aware of it's status/reliability.