Flutter Getx - "Ххх" не найдено. Вам нужно вызвать Get.put(Xxx()) - но я вызвал Get.put(Xxx())
У меня есть этот глобальный класс привязок для инициализации некоторых служб, и мне нужно, чтобы он был инициализирован сразу:
import 'package:get/get.dart';
import 'package:vepo/data/data_provider/local_data_provider.dart';
import 'package:vepo/data/data_source/local_data_source.dart';
import 'services/authentication_service.dart';
class GlobalBindings extends Bindings {
final LocalDataProvider _localDataProvider = LocalDataProvider();
@override
void dependencies() {
Get.put<AuthenticationService>(AuthenticationService(), permanent: true);
Get.put<LocalDataProvider>(_localDataProvider, permanent: true);
Get.put<LocalDataSource>(LocalDataSource(_localDataProvider),
permanent: true);
}
}
Что находится в моих начальных привязках:
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Vepo',
initialRoute: AppPages.INITIAL,
initialBinding: GlobalBindings(),
transitionDuration: const Duration(milliseconds: 500),
defaultTransition: Transition.rightToLeft,
getPages: AppPages.routes,
home: Root(),
theme: homeTheme,
);
}
}
Затем в конструкторе класса я пытаюсь "найти" его:
class UserLocalRepository extends VpService implements IUserLocalRepository {
UserLocalRepository() {
localDataSource = Get.find<LocalDataSource>();
}
LocalDataSource localDataSource;
И получите эту ошибку:
══════ Exception caught by widgets library ═══════════════════════════════════
The following message was thrown building App(dirty):
"LocalDataSource" not found. You need to call "Get.put(LocalDataSource())" or "Get.lazyPut(()=>LocalDataSource())"
The relevant error-causing widget was
App
lib/main.dart:17
When the exception was thrown, this was the stack
#0 GetInstance.find
package:get/…/src/get_instance.dart:272
#1 Inst.find
package:get/…/src/extension_instance.dart:66
#2 new UserLocalRepository
package:vepo/…/user/user_local_repository.dart:10
#3 new LoggedOutNickNameBinding
package:vepo/…/logged_out_nickname/logged_out_nick_name_binding.dart:11
#4 AppPages.routes
package:vepo/…/routes/app_pages.dart:29
...
════════════════════════════════════════════════════════════════════════════════
Это привязка, упомянутая в сообщении об ошибке:
class LoggedOutNickNameBinding extends Bindings {
LoggedOutNickNameBinding() {
_repository = Get.put(UserLocalRepository());
}
IUserLocalRepository _repository;
@override
void dependencies() {
Get.lazyPut<LoggedOutNickNameController>(
() => LoggedOutNickNameController(_repository),
);
}
}
Почему "initialBindings" не инициализированы, чтобы мое приложение могло "найти" их при запуске?
6 ответов
Я предполагаю, что существует несоответствие времени / порядка, когда вызывается ваш метод GlobalBindings.dependencies() и когда вам нужны эти ресурсы.
Вы можете попробовать инициализировать свой класс Bindings до GetMaterialApp вместо передачи класса Bindings в GetMaterialApp.
void main() async {
//WidgetsFlutterBinding.ensureInitialized(); // uncomment if needed for resource initialization
GlobalBindings().dependencies();
runApp(MyApp());
}
Касательная
Просто догадываюсь, но являются ли некоторые классы, которые вы инициализируете через Get.put, медленными (т.е. асинхронными), прежде чем они будут готовы к использованию?
Если так, вы могли бы использовать
Get.putAsync<YourClass>(() async {
// init YourClass here
return await YourClass.slowInit();
}
пример
Недавно я провел упражнение по выполнению инициализации асинхронных привязок перед загрузкой приложения для взаимодействия с пользователем. Вот код:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
enum Version {
lazy,
wait
}
// Cmd-line args/Env vars: https://stackru.com/a/64686348/2301224
const String version = String.fromEnvironment('VERSION');
const Version running = version == "lazy" ? Version.lazy : Version.wait;
void main() async {
//WidgetsFlutterBinding.ensureInitialized(); // if needed for resources
if (running == Version.lazy) {
print('running LAZY version');
LazyBindings().dependencies();
}
if (running == Version.wait) {
print('running AWAIT version');
await AwaitBindings().dependencies(); // await is key here
}
runApp(MyApp());
}
class LazyBindings extends Bindings {
@override
void dependencies() {
Get.lazyPut<MyDbController>(() => MyDbController());
}
}
/// Simulates a slow (2 sec.) init of a data access object.
/// Calling [await] dependencies(), your app will wait until dependencies are loaded.
class AwaitBindings extends Bindings {
@override
Future<void> dependencies() async {
await Get.putAsync<MyDbController>(() async {
Dao _dao = await Dao.createAsync();
return MyDbController(myDao: _dao);
});
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final MyDbController dbc = Get.find();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GetX Bindings'),
),
body: Center(
child: Obx(() => Text(dbc.dbItem.value)),
),
);
}
}
class MyDbController extends GetxController {
Dao myDao;
MyDbController({this.myDao});
RxString dbItem = 'Awaiting data'.obs;
@override
void onInit() {
super.onInit();
initDao();
}
Future<void> initDao() async {
// instantiate Dao only if null (i.e. not supplied in constructor)
myDao ??= await Dao.createAsync();
dbItem.value = myDao.dbValue;
}
}
class Dao {
String dbValue;
Dao._privateConstructor();
static Future<Dao> createAsync() async {
var dao = Dao._privateConstructor();
print('Dao.createAsync() called');
return dao._initAsync();
}
/// Simulates a long-loading process such as remote DB connection or device
/// file storage access.
Future<Dao> _initAsync() async {
await Future.delayed(Duration(seconds: 2), () => dbValue = 'Some DB data');
print('Dao._initAsync done');
return this;
}
}
В моем случае ::::
TestCartController? cartController;
if(condition){
cartController = Get.isRegistered<TestCartController>()
? Get.find<TestCartController>()
: Get.put(TestCartController());
}
но в другом виджете я имел в виду вышеуказанный контроллер как
final cartController = Get.find<TestCartController>();
Проблема несоответствия типов, потому что оба экземпляра разные, поэтому у меня возникла проблема. Я просто удалил это? отметьте, и это сработало.
TestCartController cartController;
if(condition){
cartController = Get.isRegistered<TestCartController>()
? Get.find<TestCartController>()
: Get.put(TestCartController());
}
Add fenix : true;
class AppBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<GeneralController>(() => GeneralController(), fenix: true);
Get.lazyPut<UserController>(() => UserController(), fenix: true);
}
}
это решит вашу проблему
Причина : Это происходит, когда Get.find() вызывается до Get.put(Controller). Вызов Get.find() Перед инициализацией Get.put() показывает ошибку
Решение . Просто вы можете вызвать Get.put(controller) в свой основной класс, как показано ниже. Итак, Get.find() из любого класса получит его.
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final YourController controller = Get.put(YourController());
...
@override
Widget build(BuildContext context) {
return MaterialApp(
......
}
Если ваш класс контроллера не связан ни с какимstateful/stateless
class, то вы можете инициализировать класс контроллера в основном методе следующим образом:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// init app controller
AppController appController =
await Get.putAsync<AppController>(() async => AppController(), permanent: true);
// init temp storage
await GetStorage.init();
runApp(const MyApp());
}
Убедитесь, что ваш LocalDataSource расширяет и реализует эти классы.
LocalDataSource extends GetxController implements GetxService