When I should create separate Provider class? - flutter

I have class that process data. I have two options.
1. To registration it as Provider directly:
class GetServerData extends ChangeNotifier
{
String resultDate;
getData() {
resultDate = http.get(...);
notifyListeners();
}
}
Сreate wrapper-provider class. And use it as Provider.
class ServerDataProvider extends ChangeNotifier {
String resultDate;
GetServerData getServerData = GetServerData();
getData() {
resultDate = getServerData.getData();
notifyListeners();
}
}
When I should prefer to use first variant and when second?

Related

Flutter Provider: Should I create a new Provider for every class?

Lets say I have multiple settings a user can set. Should I have one Provider which manages all settings like so:
class Settings with ChangeNotifier {
SettingsA _settingsA;
SettingsB _settingsB;
List<String> _settingsC;
SettingsA get settingsA => _settingsA;
SettingsB get settingsB => _settingsB;
List<String> get settingsC => _settingsC;
// Setters
void updateA(SettingsA settingsA) {
_settingsA = settingsA;
notifyListeners();
}
void updateB(SettingsB settingsB) {
_settingsB = settingsB;
notifyListeners();
}
void addToC(String setting) {
_settingsC.add(setting);
notifyListeners();
}
}
Or should I rather make a Provider for every object like so:
class SettingsAProvider with ChangeNotifier {
SettingsA _settingsA;
SettingsA get settingsA => _settingsA;
// Setters
void update(SettingsA settingsA) {
_settingsA = settingsA;
notifyListeners();
}
}
What is the best practise of using ChangeNotifierProviders?
In my opinion, you should use SettingAProvider,SettingBProvider,...
If you use Settings Class...
When you call updateA, it will notify all value _settingA,_settingB,_settingC,... even if unecessary.

Call super method of super class from child class

I have an abstract class A:
abstract class A {
Future<String> firstMethod();
}
and I implemented this abstract class:
class Aimp implements A {
#override
Future<String> firstMethod() async {
return "test";
}
}
I have created another abstract class:
abstract class B extends A {
Future<String> secondMethod();
}
and I implemented this abstract class:
class Bweb extends B {
#override
Future<Object> secondMethod() async {
final t = //I want to call firstMethod()
if(t.isNotEmpty()) // do sth
}
}
In the implementation of secondMethod(), how can I call the implementation of firstMethod()?
I don't want to use mixin.
I try to use with instead:
abstract class A {
Future<String> firstMethod();
}
class Aimp implements A {
#override
Future<String> firstMethod() async {
return "test";
}
}
abstract class B with Aimp {
Future<String> secondMethod();
}
class Bweb extends B {
#override
Future<String> secondMethod() async {
final String t = await firstMethod(); //Your firstMethod function
if(t.isNotEmpty) {
return t;
}
return '';
}
}
Then you need an object of Aimp class item as a field of Bweb class. Or place A class as a field for the B one.

Combining Riverpod Providers Bidirectionally

How can we access a method from the being wrapped riverpod provider?
ContentProvider can access user value from UserProvider by using "watch". There is no problem for this direction. On the other hand, UserProvider also needs access to the methods of ContentProvider. So bidirectional communication is required.
For this case, I need to call deleteContents method from UserProvider.
I don't prefer to merge them to keep logic safe.
class ContentProviderNotifier extends ChangeNotifier {
final User? currentUser;
ContentProviderNotifier({required this.currentUser});
addContent(Content content) {
content.user = currentUser?.name;
...
}
deleteContents() {
...
}
}
final contentProvider = ChangeNotifierProvider<ContentProviderNotifier>(
(ref) {
final user = ref.watch(userProvider).currentUser;
return ContentProviderNotifier(currentUser: user);
},
);
class UserProviderNotifier extends ChangeNotifier {
UserProviderNotifier();
User? currentUser;
deleteUsers(){
// here to call a method from contentProvider
deleteContents();
}
}
final userProvider = ChangeNotifierProvider<UserProviderNotifier>(
(ref) {
return UserProviderNotifier();
},
);
If I try to feed UserProvider with ContentProvider like this
final userProvider = ChangeNotifierProvider<UserProviderNotifier>(
(ref) {
final content = ref.watch(contentProvider); // <----
return UserProviderNotifier(content);
},
);
But I know, It won't make sense.
The type of 'userProvider' can't be inferred because it depends on itself through the cycle: contentProvider, userProvider.
Try adding an explicit type to one or more of the variables in the cycle in order to break the cycle.darttop_level_cycle
You can create UserProviderNotifier so it takes ref as an input, like this:
class UserProviderNotifier extends ChangeNotifier {
UserProviderNotifier(this.ref);
final Ref ref;
deleteUsers() {
// here to call a method from contentProvider
ref.watch(contentProvider.notifier).deleteContents();
}
}
final userProvider = ChangeNotifierProvider<UserProviderNotifier>(
(ref) {
return UserProviderNotifier(ref);
},
);
This section of the Riverpod docs mentions this is a common use-case.

How do I update Flutter's Riverpod values from business logic?

When using Flutter and Riverpod, how do I update its values from my business logic?
I understand that I can get and set values from the UI side.
class XxxNotifier extends StateNotifier<String> {
XxxNotifier() : super("");
}
final xxxProvider = StateNotifierProvider<XxxNotifier, int>((ref) {
return XxxNotifier();
});
class MyApp extends HookConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
// getValue
final String value = ref.watch(xxxProvider);
// setValue
context.read(xxxProvider).state = "val";
return Container();
}
}
This method requires a context or ref.
How do I get or set these states from the business logic side?
Passing a context or ref from the UI side to the business logic side might do that, but I saw no point in separating the UI and business logic. Perhaps another method exists.
Perhaps I am mistaken about something. You can point it out to me.
You can pass ref in your XxxNotifier class:
class XxxNotifier extends StateNotifier<String> {
XxxNotifier(this._ref) : super("");
final Ref _ref;
void setNewState() {
state = 'to setting';
// use `_ref.read` to read state other provider
}
}
final xxxProvider = StateNotifierProvider<XxxNotifier, int>((ref) {
return XxxNotifier(ref);
});
// or using tear-off
final xxxProvider = StateNotifierProvider<XxxNotifier, int>(XxxNotifier.new);
You can create methods in your XxxNotifier class to modify the state of your provider.
For example, your notifier class can look like this.
class TodosNotifier extends StateNotifier <List<Todo>> {
TodosNotifier(): super([]);
void addTodo(Todo todo) {
state = [...state, todo];
}
}
You can then read the provider in a callback.
ref.read(xxxProvider.notifier).addTodo(todo);

How to define concrete type from generic in Dart?

I am trying to make multiple Controller Types foo multiple Models for use with Provider in Flutter.
This is my Code:
//generic controller
class ModelController<E extends HiveObject> extends ChangeNotifier {
Box<E> _db;
ModelController(Box<E> db) {
_db = db;
}
// getters
List<E> get all => _db.values;
// create
void add(E item) {
_db.add(item);
notifyListeners();
}
void update(E item) {
item.save();
notifyListeners();
}
// delete
void delete(E item) {
item.delete();
notifyListeners();
}
}
class PacketController extends ModelController<Packet>{
PacketController(Box<Packet> db) : super(db);
}
The code for class PacketController is the only way I found to create a concrete type from a generic one.
Question:Is there a better way for this?
Shortly, I am looking for something like typedef in c++:
typedef IntVector std::vector<int>