Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on example code for addListener #352

Closed
warcayac opened this issue Dec 22, 2023 · 10 comments
Closed

Error on example code for addListener #352

warcayac opened this issue Dec 22, 2023 · 10 comments

Comments

@warcayac
Copy link

warcayac commented Dec 22, 2023

I'm following your example code

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void initState() {
    // Access the instance of the registered IAppModel
    // As we don't know for sure if IAppModel is already ready we can use getAsync
    GetIt.I
      .isReady<IAppModel>()
      .then((_) => GetIt.I<IAppModel>().addListener(update))
    ;
    // Alternative:
    // GetIt.I.getAsync<IAppModel>().addListener(update);

    super.initState();
  }

  @override
  void dispose() {
    GetIt.I<IAppModel>().removeListener(update);
    super.dispose();
  }
...

If I uncomment this line: GetIt.I.getAsync<IAppModel>().addListener(update);

I get this error message:

The method 'addListener' isn't defined for the type 'Future'.
Try correcting the name to the name of an existing method, or defining a method named 'addListener'.
@escamoteur
Copy link
Collaborator

sure, that is expected. getAsync returns a Future so you have to write it this way:

(await GetIt.I.getAsync<IAppModel>()).addListener(update);

which is what you do when you use the then.

@warcayac
Copy link
Author

I've rewritten initState method to this:

  @override
  void initState() async {
    (await GetIt.I.getAsync<IAppModel>()).addListener(update);

    super.initState();
  }

Now I get this error message:

Connecting to VM Service at ws://127.0.0.1:40499/I25uskXCZ5E=/ws
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building Builder:
_HomePageState.initState() returned a Future.
State.initState() must be a void method without an `async` keyword.
Rather than awaiting on asynchronous work directly inside of initState, call a separate method to do
this work without awaiting it.

So I rewrote it again:

  @override
  void initState() {
    _adder();
    super.initState();
  }

  void _adder() async => (await GetIt.I.getAsync<IAppModel>()).addListener(update);

Now I get this error message:

Connecting to VM Service at ws://127.0.0.1:33589/jvi4nx9cHWI=/ws
Rebuilt screen
Error: Bad state: You can only access registered factories/objects this way if they are created asynchronously
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:3  throw_
...

@escamoteur
Copy link
Collaborator

escamoteur commented Dec 22, 2023 via email

@warcayac
Copy link
Author

app_model.dart

import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';

abstract interface class IAppModel extends ChangeNotifier {
  void incrementcounter();
  int get counter;
}

class AppModel extends IAppModel {
  var _counter = 0;

  AppModel() {
    /// lets pretend we have to do some async initialization
    Future
      .delayed(const Duration(seconds: 3))
      .then((_) => GetIt.I.signalReady(this))
    ;
  }

  @override
  int get counter => _counter;

  @override
  void incrementcounter() {
    _counter++;
    notifyListeners();
  }
}

di.dart

import 'package:get_it/get_it.dart';

import '../model/app_model.dart';

void configureDependencies() {
  GetIt.I.registerSingleton<IAppModel>(AppModel(), signalsReady: true);
}

main.dart

void main() async {
  configureDependencies();
  runApp(const MyApp());
}

@escamoteur
Copy link
Collaborator

escamoteur commented Dec 22, 2023 via email

@warcayac
Copy link
Author

I'm sorry but I'm a little confused with your answer. In your example code you wrote:

    // Alternative:
    // getIt.getAsync<AppModel>().addListener(update);

This would indicate that this code

    GetIt.I
      .isReady<IAppModel>()
      .then((_) => GetIt.I<IAppModel>().addListener(update))
    ;

can be replaced by this single line: getIt.getAsync<AppModel>().addListener(update); however you suggest an additional change and it brings other changes and errors. After you say:

If you doesn't have any asynchronous inititialisation function, you don't need to use already or getAsync at all

So this alternative way you wrote in your example code doesn't apply to it, it's correct? If so, shouldn't there be another example where getAsync is corectly used and not here that brings confusion? If I'm wrong, I ask you please to show me the correct way to use it in your code.

@escamoteur
Copy link
Collaborator

escamoteur commented Dec 22, 2023 via email

@warcayac
Copy link
Author

@escamoteur
Copy link
Collaborator

escamoteur commented Dec 22, 2023 via email

@escamoteur
Copy link
Collaborator

I added a comment in the example for clarification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants