Flutter - How to retrieve an implemented class with Get.find after registered with Get.put using GetX? - flutter

I have a class called GetConnectApiHelper that implemented an abstraction called IApiHelper, I need to register this class with Get.put inside Bindings and retrieve the implementation inside an abstraction variable but when I try to do that I get an error about "the abstraction is not registered".
How can I inject the dependency correctly making it easy to change in case I need to replace with http, dio etc...(clean architecture)
abstract class IApiHelper {}
class GetConnectApiHelper extends GetxService implements IApiHelper {}
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put(GetConnectApiHelper());
Get.put(SignInController());
}
}
class SignInController extends GetxController {
final IApiHelper apiHelper = Get.find(); // This throws the exception
}
======== Exception caught by widgets library =======================================================
The following message was thrown building Builder(dirty):
"IApiHelper" not found. You need to call "Get.put(IApiHelper())" or "Get.lazyPut(()=>IApiHelper())"

I found a solution. I can set the Interface as a Type and then register the implementation I want to be retrieved.
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put<IApiHelper>(GetConnectApiHelper());
Get.put(SignInController());
}
}
class SignInController extends GetxController {
final IApiHelper apiHelper = Get.find();
}
print(apiHelper.runtimeType); // it prints Instance of 'GetConnectApiHelper'
Or I can inject the implementation.
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put<IApiHelper>(GetConnectApiHelper());
Get.put(SignInController(apiHelper: Get.find()));
}
}
class SignInController extends GetxController {
final IApiHelper apiHelper;
SignInController({required this.apiHelper})
}

GetX finds its dependencies based on its exact types so you need to use Get.find<GetConnectApiHelper>()
updated:
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put(GetConnectApiHelper());
Get.put(SignInController<GetConnectApiHelper>());
}
}
class SignInController<T extends IApiHelper> extends GetxController {
final IApiHelper apiHelper = Get.find<T>();
}

Related

Error: Type argument 'T' doesn't conform to the bound 'Object' of the type variable 'T' on 'GetIt.call'. After migrating to Null Safety

I'm in the process of migrating over a large project to null safety and I'm coming across a strange error I'm not entirely sure how to fix.
"Error: Type argument 'T' doesn't conform to the bound 'Object' of the type variable 'T' on 'GetIt.call'."
class BaseView<T extends BaseProvider?> extends StatefulWidget {
final Widget Function(BuildContext context, T value, Widget? child)? builder;
final Function(T)? onModelReady;
BaseView({this.builder, this.onModelReady});
#override
_BaseViewState<T> createState() => _BaseViewState<T>();
}
class _BaseViewState<T extends BaseProvider?> extends State<BaseView<T?>> {
T model = locator<T>(); <---- This is throwing it
#override
void initState() {
if (widget.onModelReady != null) {
widget.onModelReady!(model);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T?>(
create: (context) => model,
child: Consumer<T>(builder: widget.builder!),
);
}
}
I can't find much info on this error and so far any method I've tried hasn't worked out. Can anyone be of assistance?
I'm using Provider for state management and BaseView is what wraps all my other views during build; e.g.:
class EquipmentMainView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BaseView<EquipmentProvider>(
onModelReady: (model) async {
model.getAllFunctions();
},..
Posting here for anyone else that might eventually run across this in the future, just changed the nullability of BaseProvider suggested by jamesdlin by changing
class BaseView<T extends BaseProvider?>
to
class BaseView<T extends BaseProvider>
I had similar issues when I upgraded to flutter 2.0 I made the generic methods in Generic class to explicitly extends Base class Object i.e
from:
import 'package:get_it/get_it.dart';
class PoultryBabaRegistry<T> {
static GetIt _getIt = GetIt.instance;
static void register<T>(T model) {
_getIt.registerSingleton<T extends Object >(model, signalsReady: true);
}
static void remove<T>(T model) {
_getIt.unregister<T extends Object>(instance:model);
}
static T getIt<T>() {
return _getIt.get<T>();
}
}
to:
class PoultryBabaRegistry<T extends Object> {
static GetIt _getIt = GetIt.instance;
static void register<T extends Object>(T model) {
_getIt.registerSingleton<T >(model, signalsReady: true);
}
static void remove<T extends Object>(T model) {
_getIt.unregister<T>(instance:model);
}
static T getIt<T extends Object>() {
return _getIt.get<T>();
}
}

Dart / Flutter - class doesn't have to implement abstract class's abstract methods?

in Flutter we have class
abstract class PreferredSizeWidget implements Widget {
Size get preferredSize;
}
and
#immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
#protected
#factory
Element createElement();
#override
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
#override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
#override
#nonVirtual
bool operator ==(Object other) => super == other;
#override
#nonVirtual
int get hashCode => super.hashCode;
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
static int _debugConcreteSubtype(Widget widget) {
return widget is StatefulWidget ? 1 :
widget is StatelessWidget ? 2 :
0;
}
}
My question is: Why if we mix in PreferredSizeWidget class we don't have to have implementation for all of the abstract class Widget methods and abstract methods?
I tried to mock up some code
class A implements B {}
abstract class B extends C {}
abstract class C {
void test() {
print("test");
}
}
and got error
Error: The non-abstract class 'A' is missing implementations for these members:
- C.test
class A implements B {
^
lib/main.dart:16:8:
Haven’t run it myself, but in your case A isn’t abstract anymore so it
has to implement everything, in the case of PreferredSizeWidget - you
usually extend/implement/ mixin it on a widget (which already
implements everything from widget) thus leaving you with only
preferredSize
#Norbert515's answer.
The main point is that even though if we mixin/extend PreferredSizeWidget we actually implement all of the Widget methods but as we usually mixin it on a Widget we don't have to make an implicit override of the methods.

How to access provider in model class

I have a class which is not a widget , so it doesn't have any context. So is there any way I can access Class with ChangeNotifier within this model class.
Model Class
class MyRouteObserver extends RouteObserver<PageRoute<dynamic>> {
#override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
Provider.of<MyCass>(context, listen: false).restore(); // How I can do this ? as I dont have context here
super.didPop(route, previousRoute);
if (previousRoute is PageRoute && route is PageRoute) {
_sendScreenView(previousRoute);
}
}
}
My Class
class MyClass with ChangeNotifier {
void restore() {
.. Some logic
}
}
Add context filed to your class
final BuildContext context;
then add it to constructor
const MyRouteObserver(this.context);
so you can pass build context to your class from your widget class

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!

How to use ChangeNotifier with a abstract class in Flutter?

In my dart application, I wanted to use ChangeNotifier for my authentication class.
I have an abstract class and another class implements the methods.
abstract class AuthBase {
Future<void> signIn(String email, String password);
Future<void> signUp(String email);
Future<void> signOut();
}
class Auth with ChangeNotifier implements AuthBase {
...
}
As you can see ChangeNotifier is not used with the base class.
What I would like to do is use ChangeNotifier with the abstract class. But not sure how to override the methods in Auth class;
#override
void addListener(listener) {
// TODO: implement addListener
}
#override
void dispose() {
// TODO: implement dispose
}
#override
// TODO: implement hasListeners
bool get hasListeners => throw UnimplementedError();
#override
void notifyListeners() {
// TODO: implement notifyListeners
}
#override
void removeListener(listener) {
// TODO: implement removeListener
}
Can someone provide some help with this?
Provider documentation has an example for that case: https://github.com/rrousselGit/provider#can-i-consume-an-interface-and-provide-an-implementation
abstract class ProviderInterface with ChangeNotifier {
...
}
class ProviderImplementation with ChangeNotifier implements ProviderInterface {
...
}
class Foo extends StatelessWidget {
#override
build(context) {
final provider = Provider.of<ProviderInterface>(context);
return ...
}
}
ChangeNotifierProvider<ProviderInterface>(
create: (_) => ProviderImplementation(),
child: Foo(),
),