Flutter Getx - "Xxx" 未找到。您需要调用 "Get.put(Xxx())" - 但我调用了 Get.put(Xxx())

Flutter Getx - "Xxx" not found. You need to call "Get.put(Xxx())" - But i have called Get.put(Xxx())

我有这个全局绑定 class 来初始化一些服务,我需要立即初始化它:

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);
  }
}

在我的 initialBindings 中:

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 构造函数中我尝试“找到”它:

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”没有初始化,以便我的应用程序可以在应用程序启动时“找到”它们?

我猜你的 GlobalBindings.dependencies() 方法被调用的时间和你需要这些资源的时间不匹配。

您可以尝试初始化您的绑定 class 先于 到 GetMaterialApp,而不是将您的绑定 class 传递给 GetMaterialApp.

void main() async {
  //WidgetsFlutterBinding.ensureInitialized(); // uncomment if needed for resource initialization
  GlobalBindings().dependencies();
  runApp(MyApp());
}

切线

这里只是猜测,但是您通过 Get.put 初始化的某些 class 是否在准备好使用之前启动缓慢(即异步)?

如果是这样你可以使用

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: 
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 {
    dbValue = await Future.delayed(Duration(seconds: 2), () => '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());

}

原因 : 当Get.find() 在Get.put(Controller) 之前调用时发生。在初始化 Get.put() 之前调用 Get.find() 显示错误

解决方案 :只需将 Get.put(controller) 调用到主 class 中,如下所示。那么来自任何 class 的 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(
    ......
  
}