UnregisteredInstance after update to 6.1.1
after update to modular 6.1.1 I'm getting an UnregisteredInstance after the bindings. I saw the auto_injector got some changes in da310a074e5d458324e8fe87465736c2001c9019
I've tried to add a "key" to the bindings and it only change the class it can't found. I suspect the absent 'key' may be the culprit
Olá. Acredito que fiz a correção pra esse problema, está em beta por enquanto. Estamos avaliando.
O mesmo problema aqui.
testei com a versão 6.2.0-beta.4, mas o problema se manteve
Corrigido o bug: Quando era registrado uma instância em um Módulo ancestral ele ficava disponível para os filhos automaticamente. Isso gerava problemas de compreenção quando o módulo estava separado do app base. Agora recomendamos a criação de um Módulo global, exportar os binds e importar nos módulos.
como são binds do app_module, eu moveria para exportBinds e usaria import nos modulos filhos. isso? No caso de binds que usam outros binds do mesmo módulo, teria de importar no app_module tb?
Isso. Mas eu sugiro que crie um Módulo como CoreModule ou CommonModule e coloque lá todos os dados globais.
@jacobaraujo7 nao é possivel mudar o ciclo de vida para chamar primeiramente o binds e depois o imports? Quando eu chamo meu AppModule, ele tem minhas injections globais (um controller de logs, por exemplo) que eu injeto no binds do próprio AppModule. Essa mesma classe de logs é usada em AuthModule, que eu injeto em AppModule atraves do import do AppModule. Mas quando rodo o app, da erro de que nao foi possivel encontrar essa classe de log em AuthModule, pois ele ainda nao foi injetado em AppModule.
@jacobaraujo7 nao é possivel mudar o ciclo de vida para chamar primeiramente o binds e depois o imports? Quando eu chamo meu AppModule, ele tem minhas injections globais (um controller de logs, por exemplo) que eu injeto no binds do próprio AppModule. Essa mesma classe de logs é usada em AuthModule, que eu injeto em AppModule atraves do import do AppModule. Mas quando rodo o app, da erro de que nao foi possivel encontrar essa classe de log em AuthModule, pois ele ainda nao foi injetado em AppModule.
Sendo assim não seria melhor importar o controlador de logs a partir de um CoreModule? No ciclo de vida atual primeiro são resolvidos os exports depois os binds, mas os binds exports do módulo não sao visiveis no módulo current.
@jacobaraujo7 nao é possivel mudar o ciclo de vida para chamar primeiramente o binds e depois o imports? Quando eu chamo meu AppModule, ele tem minhas injections globais (um controller de logs, por exemplo) que eu injeto no binds do próprio AppModule. Essa mesma classe de logs é usada em AuthModule, que eu injeto em AppModule atraves do import do AppModule. Mas quando rodo o app, da erro de que nao foi possivel encontrar essa classe de log em AuthModule, pois ele ainda nao foi injetado em AppModule.
Sendo assim não seria melhor importar o controlador de logs a partir de um CoreModule? No ciclo de vida atual primeiro são resolvidos os exports depois os binds, mas os binds exports do módulo não sao visiveis no módulo current.
@jacobaraujo7 também tentei fazer isso, mas acontecem alguns problemas:
No App Module eu estou importando as dependencias globais do meu app, as que uso em AppModule e AuthModule, como a eventLog e crashLog.
No entando, quando executo o app, AuthModule nao encontra as dependencias ja injetadas em AppModule atraves do import. Como uso microfront baseado em packages, AuthModule nao tem acesso a algumas classes que eu optei por colocar apenas no base_app, como o EnvironmentEntity. O que ocorria de forma fácil no modular 5.x era a definicao dos AuthModule.exportedBinds dentro dos binds do AppModule e as dependencias ficavam no escopo global. Agora, aparentemente, a solucao seria colocar GlobalModule tambem dentro de AuthModule, mas pra que, se eu ja to colocando ele em AppModule que, em teoria, daria acesso a todos os meus outros módulos?
Outro fator que nao deveria influenciar no Modular 6.x era o commit do auto_injector, mas sempre recebo este alerta quando executo o app:
@leobidoous-gen POde me mostrar aqui no discord?
Também estou exatamente com o mesmo problema, tenho um CoreModule no meu imports, e meu outro módulo não consegue enxergar nenhuma dependência do CoreModule. Estou com a versão flutter_modular: ^6.3.1
class AppModule extends Module {
final Isar isar;
final SharedPreferences sharedPreferences;
AppModule(this.isar, this.sharedPreferences);
@override
List<Module> get imports => [
CoreModule(isar, sharedPreferences),
TicketsModule(),
];
@override
void routes(RouteManager r) {
r.child('/', child: (context) => const HomePage());
}
}
Meu TicketsModule.exportedBinds() não encontra Isar, nem SharedPreferences, nem outros exportedBinds do CoreModule importado no módulo pai.
Nem mesmo numa segunda tentativa, onde tentei importar o CoreModule dentro do TicketsModule. (Além de ter que passar parâmetros de classe em classe por causa da remoção do AsyncBinds)
lass TicketsModule extends Module {
final Isar isar;
final SharedPreferences sharedPreferences;
TicketsModule(this.isar, this.sharedPreferences);
@override
List<Module> get imports => [
CoreModule(isar, sharedPreferences),
];
@override
void exportedBinds(Injector i) {
i.add<TicketsDataSource>(IsarTicketsDataSource.new);
i.add<TicketsRepository>(TicketsRepositoryImpl.new);
...
}
O erro é recebido:
The injector(tag: TicketsModule_Imported) is not committed.
It is recommended to call the "commit()" method after adding instances.
UnregisteredInstance: Isar not registered.
Trace: TicketsRepository->TicketsDataSource->Isar
TicketsRepository => TicketsDataSource => Isar
package:auto_injector/src/auto_injector_base.dart 261:7 AutoInjectorImpl.get
package:auto_injector/src/auto_injector_base.dart 32:12 Injector.call
package:casadasapostas3/core/features/tickets/tickets_module.dart 98:10 TicketsModule.exportedBinds
package:modular_core/src/tracker.dart 260:22 _Tracker._createExportedInjector
package:modular_core/src/tracker.dart 271:30 _Tracker._createInjector
package:modular_core/src/tracker.dart 202:25 _Tracker.bindModule
package:flutter_modular/src/infra/services/module_service_impl.dart 25:13 ModuleServiceImpl.bind
package:flutter_modular/src/domain/usecases/bind_module.dart 17:26 BindModuleImpl.call
Também estou exatamente com o mesmo problema, tenho um CoreModule no meu imports, e meu outro módulo não consegue enxergar nenhuma dependência do CoreModule. Estou com a versão flutter_modular: ^6.3.1
class AppModule extends Module { final Isar isar; final SharedPreferences sharedPreferences; AppModule(this.isar, this.sharedPreferences); @override List<Module> get imports => [ CoreModule(isar, sharedPreferences), TicketsModule(), ]; @override void routes(RouteManager r) { r.child('/', child: (context) => const HomePage()); } }Meu TicketsModule.exportedBinds() não encontra Isar, nem SharedPreferences, nem outros exportedBinds do CoreModule importado no módulo pai.
Nem mesmo numa segunda tentativa, onde tentei importar o CoreModule dentro do TicketsModule. (Além de ter que passar parâmetros de classe em classe por causa da remoção do AsyncBinds)
lass TicketsModule extends Module { final Isar isar; final SharedPreferences sharedPreferences; TicketsModule(this.isar, this.sharedPreferences); @override List<Module> get imports => [ CoreModule(isar, sharedPreferences), ]; @override void exportedBinds(Injector i) { i.add<TicketsDataSource>(IsarTicketsDataSource.new); i.add<TicketsRepository>(TicketsRepositoryImpl.new); ... }O erro é recebido:
The injector(tag: TicketsModule_Imported) is not committed. It is recommended to call the "commit()" method after adding instances. UnregisteredInstance: Isar not registered. Trace: TicketsRepository->TicketsDataSource->Isar TicketsRepository => TicketsDataSource => Isar package:auto_injector/src/auto_injector_base.dart 261:7 AutoInjectorImpl.get package:auto_injector/src/auto_injector_base.dart 32:12 Injector.call package:casadasapostas3/core/features/tickets/tickets_module.dart 98:10 TicketsModule.exportedBinds package:modular_core/src/tracker.dart 260:22 _Tracker._createExportedInjector package:modular_core/src/tracker.dart 271:30 _Tracker._createInjector package:modular_core/src/tracker.dart 202:25 _Tracker.bindModule package:flutter_modular/src/infra/services/module_service_impl.dart 25:13 ModuleServiceImpl.bind package:flutter_modular/src/domain/usecases/bind_module.dart 17:26 BindModuleImpl.call
Peria testar na versao 6.3.2?
@jacobaraujo7 Houve um avanço, para o exemplo de baixo que mostrei, onde o Core é importado diretamente no submodule do TicketsModule, a dependência é encontrada com sucesso aqui, a atualização resolveu o problema nessa parte.
i.add<TicketsDataSource>(IsarTicketsDataSource.new);
i.add<TicketsRepository>(TicketsRepositoryImpl.new);
Mas agora surge outro problema logo em baixo onde uso um addInstance. Nesse ponto do addInstance não encontra as dependências.
i.addInstance(
DetectDatabaseAndImportItAutomaticallyUseCase(
i(),
i(),
i(),
i(),
OldAppTicketsRepositoryImpl(
i<BlueAppOldAppTicketsDataSource>(),
),
OldAppTicketsRepositoryImpl(
i<ZenAppOldAppTicketsDataSource>(),
),
),
);
Ele fica dando aquela mensagem de erro:
It is recommended to call the "commit()" method after adding instances.
O uso desse commit() faria o addInstance resolver as dependências?
Já para os imports do parent, não reconhece nem aí. Imagino que tenha a ver com o Phantom Dependencies fix da 6.3.0, tem alguma issue ou discussion do porquê da alteração? Porque pra fazer a migração do v5 para o v6, agora com vários submódulos, to tendo que repassar várias async dependencies resolvidas no main, pra dentro de cada módulo até chegar no submódulo que pretendo incluir com o CoreModule, há alguma recomendação pra evitar isso? Instanciar o CoreModule no main.dart como variável global e usar a instância seria uma solução adequada? Na v5 os imports passavam para os filhos, e aqui estava funcionando tudo ok dessa forma.
@FernandoUFS Pq vc está usando assim em vez de:
i.add(DetectDatabaseAndImportItAutomaticallyUseCase.new);
i.add(OldAppTicketsRepositoryImpl.new);
i.add(OldAppTicketsRepositoryImpl.new);
?
@jacobaraujo7 Depois do meu comentário busquei o uso de Generics pra poder usar assim como você falou e consegui, só que precisei sair especificando o tipo de classe em classe até chegar onde eu queria.
O motivo de eu ter usado como mandei anteriormente, era pra que na injeção de dependência eu pudesse especificar qual OldAppTicketsDataSource o use case iria utilizar, sem ficar passando o tipo genérico. Me fez escrever menos código na V5 do modular.
O construtor do meu DetectDatabaseAndImportItAutomaticallyUseCase recebe dois repositories, onde o tipo do repository é o mesmo: OldAppTicketsRepositoryImpl, mas o tipo que os dois repositories recebem do datasource é diferente, por isso o:
i<BlueAppOldAppTicketsDataSource>(),
i<ZenAppOldAppTicketsDataSource>(),
Perceba que no exemplo que você deu, você colocou repetido:
i.add(OldAppTicketsRepositoryImpl.new);
i.add(OldAppTicketsRepositoryImpl.new);
Resolvi na V6 da seguinte forma:
class DetectDatabaseAndImportItAutomaticallyUseCase<TDataSource1 extends OldAppTicketsDataSource, TDataSource2 extends OldAppTicketsDataSource> {
final ...;
final ...;
final TicketsRepository ticketsRepository;
final OldAppTicketsRepository<TDataSource1> app1OldAppTicketsRepository;
final OldAppTicketsRepository<TDataSource2> app2OldAppTicketsRepository;
final SettingsRepository settingsRepository;
... constructor
}
i.add(DetectDatabaseAndImportItAutomaticallyUseCase<BlueAppOldAppTicketsDataSource, ZenAppOldAppTicketsDataSource>.new);
@FernandoUFS Quando for assim vc pode usar uma função anonima:
i.add(() => DetectDatabaseAndImportItAutomaticallyUseCase<BlueAppOldAppTicketsDataSource, ZenAppOldAppTicketsDataSource>());
Obrigado pela dica @jacobaraujo7, deu certo com a função anônima. Consegui fazer do jeito antigo com ela.
E sobre a motivação da remoção do AsyncBind há algum post ou vídeo sobre isso? e os meios indicados para fazer no Modular v6?
Na v5 eu tinha, e agora preciso resolver as instâncias no main e passar via construtor de módulo até chegar no último submodulo, e como é algo do Core eu to precisando repassar pra vários submódulos, já que o import do pai não passa mais para os filhos. Ainda n achei um jeito legal de fazer isso sem repetição.
class CoreModule extends Module {
@override
List<Bind<Object>> get binds => [
AsyncBind((i) => SharedPreferences.getInstance(), export: true),
AsyncBind((i) async {
final dir = await getApplicationDocumentsDirectory();
Isar isar = await Isar.open(
[IsarTicketSchema, IsarSelectionSchema, IsarTagSchema, IsarMatchResultSchema],
directory: dir.path,
);
return isar;
}, export: true),
];
}
@FernandoUFS Veja este vídeo do Jacob: https://www.youtube.com/watch?v=xAiq8DzR65s A partir do minuto: 1h 10m 32s
6.3.2 com modulo somente de exports funcionou aqui
Here is my case where imports broke after 6.1.1. I had modules that had dependencies on each other.
For example Module1 depends on Module2
class Class1_1 {}
class Class1_2 {
Class1_2(this.class1);
final Class2_2 class1;
}
class Module1 extends Module {
@override
void exportedBinds(Injector i) {
i.add(Class1_1.new);
i.add(Class1_2.new); /// needs [Class2_2] from [Module2]
}
}
and Module2 depends on Module1
class Class2_1 {
Class2_1(this.class1);
final Class1_1 class1;
}
class Class2_2 {}
class Module2 extends Module {
@override
void exportedBinds(Injector i) {
i.add(Class2_1.new); /// needs [Class1_1] from [Module1]
i.add(Class2_2.new);
}
}
Before version 6 I could just put them in one AppModule module, but now I am getting UnregisteredInstance error
class AppModule extends Module {
@override
List<Module> get imports => [ /// these modules cannot see [exportedBinds] of each other
Module1(),
Module2(),
];
}
And I cannot use imports in Module1 and Module2, because it will cause StackOverflowError due recursion.
As a solution it would be great to give us a option, that makes modules, defined in imports in AppModule to see exportedBinds of each other like it was before.
@0x384c0, create a third module and put the classes in common from modules 1 and 2. Import this third module into modules 1 and 2
Estou tendo um problema similar, mas um pouco diferente. Tenho um módulo global que exporta as binds globais, porém o erro parece estar atrelado a ordem de declaração dos Binds que contêm key. Por exemplo, tenho 3 binds com keys, o primeiro bind(com key) da erro ao chamar a classe em questão. Se eu remover essa key e deixar rolar a injeção por tipagem a segunda key, que nesse caso seria a primeira, começa a dar erro.
Alguém sabe o que pode ser?
OBS: Estou utilizando a versão mais recente, que no momento é a 6.3.2
Também estou enfrentando algumas dificuldades para conseguir atualizar da versão 5 para a 6.
Quem fica responsável pelo ciclo de vida dos binds de módulos importados? Pois nos meus testes eles nunca são removidos da memória, mesmo quando ocorre o dispose do módulo proprietário ou do módulo que fez o import.
Na versão 5 eu não precisava usar import porque era possível "reaproveitar" o bind nos demais módulos. @jacobaraujo7, consegue dar um help por favor?