Getx: Get.lazyPut with tag lead to an exception

Created on 6 Sep 2020  ยท  2Comments  ยท  Source: jonataslaw/getx

Describe the bug
It seems that calling Get.lazyPut() with a tag parameter throw an exception.

To Reproduce
Steps to reproduce the behavior:

  1. Create a simple controller
  2. Call Get.lazyPut() with this controller, assign a tag to it
  3. Open the page using this controller
  4. The app crashes with an exception saying IsInit is called on null

Expected behavior
Everything should work normally...

Flutter Version:
1.20.0

Getx Version:
3.8.0

Describe on which device you found the bug:
Samsung SM A7000

Minimal reproduce code

class PageController extends GetxController {
  String get text => "Example";
}

class PageBindings extends Bindings {
  @override
  void dependencies() => Get.lazyPut(() => PageController(), tag: "special-tag");
}

class Page extends GetView<PageController> {
  @override
  Widget build() => Container(child: Text(controller.text));
}

Possible solution
After a debugging session on the get code, I've found this line. The _lazyPuted_ dependency is not registered with the tag using Get.put() when calling Get.find() for the first time for that dependency. So the call to _initDependencies<S>(name: tag) will never find the right dependency.

I think changing this line to S _value = put<S>(_factory[key].builder() as S, tag: tag); will solve the issue...

bug

All 2 comments

@na2axl You can't use a GetView or GetWidget when you register your instance with a tag.
Those Widgets only makes use of the generic type <T>.
You can only use it with Get.find<Controller>(tag:"special-tag")...
tags are meant to give you the ability to use multiple different instances of the same type, that's why Get's dependency injection system, is not just a Singleton factory.

If you actually believe this is an issue, please create another one, and maybe we discuss another implementation with a function call (instead of a getter) like controller( tag: "something" ).

class PageController extends GetxController {
  String get text => "Example";
}

class PageBindings extends Bindings {
  @override
  void dependencies() => Get.lazyPut(() => PageController(), tag: "special-tag");
}

class Page extends StatelessWidget {
  PageController get controller => Get.find<PageController>(tag: "special-tag");

  @override
  Widget build() => Container(child: Text(controller.text));
}

Sorry @roipeker is my fault, I've just wanted to show a quick example, and I've used GetWidget as an _habit_. But no, this is not the reason of the problem. As I said, when you do Get.lazyPut(() => Controller(), tag: "tag"), the next call to Get.find(tag: "tag") will throw an exception saying The getter isInit was called on null. This is not beacause of GetWidget. And I think it is because of that:

S find<S>({String tag}) {
    final key = _getKey(S, tag);
    if (isRegistered<S>(tag: tag)) {
      if (_singl[key] == null) {
        if (tag == null) {
          throw 'Class "$S" is not register';
        } else {
          throw 'Class "$S" with tag "$tag" is not register';
        }
      }
      _initDependencies<S>(name: tag);
      return _singl[key].getDependency() as S;
    } else {
      if (!_factory.containsKey(key)) {
        // ignore: lines_longer_than_80_chars
        throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
      }

      GetConfig.log('Lazy instance "$S" created');

      var _value = put<S>(_factory[key].builder() as S); // THIS LINE HERE

      _initDependencies<S>(name: tag);

      if (GetConfig.smartManagement != SmartManagement.keepFactory &&
          !_factory[key].fenix) {
        _factory.remove(key);
      }

      return _value;
    }
  }

The dependency created using lazyPut with a tag is registered at the right time using put but without tag, so in _initDependencies:

bool _initDependencies<S>({String name}) {
    final key = _getKey(S, name);
    final isInit = _singl[key].isInit; // THIS LINE THROWS THE EXCEPTION
    if (!isInit) {
      _startController<S>(tag: name);
      _singl[key].isInit = true;
      if (GetConfig.smartManagement != SmartManagement.onlyBuilder) {
        _registerRouteInstance<S>(tag: name);
      }
    }
    return true;
  }

The generated key doesn't match any dependency and the array access return a null value...

I'm reopening the issue, so please @roipeker or @jonataslaw investigate in this. Sorry for the last time I've not well explained the problem because I was a bit busy and I wanted to write something quickly.

This is a part of the stack trace:

โ•โ•โ•ก EXCEPTION CAUGHT BY WIDGETS LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following NoSuchMethodError was thrown building Builder(dirty):
The getter 'isInit' was called on null.
Receiver: null
Tried calling: isInit
The relevant error-causing widget was:
  Navigator-[LabeledGlobalKey<NavigatorState>#a65be]

lib\โ€ฆ\chat\chat_page.dart:111
When the exception was thrown, this was the stack:
#0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:51:5)
#1      GetInstance._initDependencies           package:get/โ€ฆ/instance/get_instance.dart:150
#2      GetInstance.find                                  package:get/โ€ฆ/instance/get_instance.dart:231
#3      Inst.find                                               package:get/โ€ฆ/instance/extension_instance.dart:54
#4      new ChatMessaging                           package:isintu_chat/โ€ฆ/widgets/chat_messaging_widget.dart:46
#5      ChatPage.build.<anonymous closure>.<anonymous closure>.<anonymous closure>    lib\โ€ฆ\chat\chat_page.dart:126
#6      GetPageRoute.buildPage 
Was this page helpful?
0 / 5 - 0 ratings

Related issues

williamsilva-98 picture williamsilva-98  ยท  4Comments

ChiwanAhn picture ChiwanAhn  ยท  4Comments

Grohden picture Grohden  ยท  3Comments

aztecrabbit picture aztecrabbit  ยท  3Comments

omartinma picture omartinma  ยท  3Comments