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/statelessclass, то вы можете инициализировать класс контроллера в основном методе следующим образом:

      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
Другие вопросы по тегам