fluttercommunity / get_it

Get It - Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App. Maintainer: @escamoteur
https://pub.dev/packages/get_it
MIT License
1.36k stars 149 forks source link

Error on example code for addListener #352

Closed warcayac closed 10 months ago

warcayac commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

Actually using then in initstate is often a good way to do this. But your new error seems to say that this object was not registered using one of the async registration methods. How do you register IAppModel Am 22. Dez. 2023, 15:11 +0100 schrieb William Arcaya C. @.***>:

I've rewritten initState method to this: @override void initState() async { (await GetIt.I.getAsync()).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()).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/ddcruntime/errors.dart 294:3 throw ... — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

warcayac commented 11 months ago

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 commented 11 months ago

If you doesn't have any asynchronous inititialisation function, you don't need to use already or getAsync at all Am 22. Dez. 2023, 15:34 +0100 schrieb William Arcaya C. @.***>:

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(AppModel(), signalsReady: true); } main.dart void main() async { configureDependencies(); runApp(const MyApp()); } — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

warcayac commented 11 months ago

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 commented 11 months ago

Can you please point me to the place where you saw that example? It's possible that I have to add some clarifications in the Readme.

In your case you don't need any getAsync and no isReady or allready Am 22. Dez. 2023, 15:58 +0100 schrieb William Arcaya C. @.***>:

I'm sorry but I'm a little confused with your answer. In your example code you wrote: // Alternative: // getIt.getAsync().addListener(update); This would indicate that this code GetIt.I .isReady() .then((_) => GetIt.I().addListener(update)) ; can be replaced by this single line: getIt.getAsync().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. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

warcayac commented 11 months ago

https://github.com/fluttercommunity/get_it/blob/master/example/lib/main.dart

line 50

escamoteur commented 11 months ago

I revisit that. It's definitely nothing you will use much in that exact way. Especially with signalReady=true Am 22. Dez. 2023, 16:05 +0100 schrieb William Arcaya C. @.***>:

https://github.com/fluttercommunity/get_it/blob/master/example/lib/main.dart line 50 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

escamoteur commented 10 months ago

I added a comment in the example for clarification