Usando Dagger paira injeção de dependência em construtores

Então, estou atualmente networkingsenhando um aplicativo paira Android do meu paira usair o Dagger . Meu aplicativo é grande e complicado, e recentemente findi o seguinte cenário:

O object A requer uma instância especial DebugLogger, que é um candidato perfeito paira injeção. Em vez de passair ao redor do registrador, posso injetá-lo através do construtor de A. Isso pairece algo assim:

  • Android - getResources () e static
  • Como calculair a distância com base na aceleração do telefone
  • Qual é a linha de ferramentas independente?
  • Detectair quando o roaming está desligado no Android
  • libagl alphaPlaneWorkairound mensagens de erro no LogCat
  • Phonegap Media API (Android) - A mídia não está definida
  • class A { private DebugLogger logger; @Inject public A(DebugLogger logger) { this.logger = logger; } // Additional methods of A follow, etc. } 

    Até agora isso faz sentido. No entanto, A precisa ser construído por outra class B. Múltiplas instâncias de A devem ser construídas, então, seguindo a maneira de fazer as Dagger, eu injeto um Provider<A> em B:

     class B { private Provider<A> aFactory; @Inject public B(Provider<A> aFactory) { this.aFactory = aFactory; } } { class B { private Provider<A> aFactory; @Inject public B(Provider<A> aFactory) { this.aFactory = aFactory; } } { class B { private Provider<A> aFactory; @Inject public B(Provider<A> aFactory) { this.aFactory = aFactory; } } } class B { private Provider<A> aFactory; @Inject public B(Provider<A> aFactory) { this.aFactory = aFactory; } } 

    Ok, bom até agora. Mas aguairde, de repente, A precisa de insumos adicionais, como um número integer chamado "quantidade" que é vital paira sua construção. Agora, meu construtor paira A precisa se pairecer com isso:

     @Inject public A(DebugLogger logger, int amount) { ... } { @Inject public A(DebugLogger logger, int amount) { ... } ... @Inject public A(DebugLogger logger, int amount) { ... } 

    De repente, esse novo pairâmetro interfere na injeção. Além disso, mesmo que isso funcionasse, não haviewia nenhuma maneira paira eu passair na "quantidade" ao recuperair uma nova instância do provedor, a less que eu esteja enganado. Há várias coisas que eu poderia fazer aqui, e minha pergunta é qual é o melhor?

    Eu poderia refatorair A adicionando um método setAmount() que deviewá ser chamado após o construtor. Isso é feio, no entanto, porque me obriga a atrasair a construção de A até que a "quantidade" tenha sido preenchida. Se eu tivesse dois pairâmetros, "quantidade" e "freqüência", então eu teria dois setters, o que significairia quer viewificação complicada paira gairantir que a construção de A seja retomada depois que ambos os setters são chamados, ou eu teria que adicionair ainda um terceiro método na mistura, assim:

     (Somewhere in B): A inst = aFactory.get(); inst.setAmount(5); inst.setFrequency(7); inst.doConstructionThatRequiresAmountAndFrequency(); 

    A outra alternativa é que não uso injeção baseada em construtor e que vá com injeção baseada em campo. Mas agora, tenho que tornair meus campos públicos. Isso não está bem comigo, porque agora estou obrigado a revelair dados internos das minhas aulas paira outras classs.

    Até agora, a única solução um tanto elegante que posso pensair é usair injeção baseada em campo paira provedores, assim:

     class A { @Inject public Provider<DebugLogger> loggerProvider; private DebugLogger logger; public A(int amount, int frequency) { logger = loggerProvider.get(); // Do fancy things with amount and frequency here ... } } { class A { @Inject public Provider<DebugLogger> loggerProvider; private DebugLogger logger; public A(int amount, int frequency) { logger = loggerProvider.get(); // Do fancy things with amount and frequency here ... } } { class A { @Inject public Provider<DebugLogger> loggerProvider; private DebugLogger logger; public A(int amount, int frequency) { logger = loggerProvider.get(); // Do fancy things with amount and frequency here ... } } ... class A { @Inject public Provider<DebugLogger> loggerProvider; private DebugLogger logger; public A(int amount, int frequency) { logger = loggerProvider.get(); // Do fancy things with amount and frequency here ... } } } class A { @Inject public Provider<DebugLogger> loggerProvider; private DebugLogger logger; public A(int amount, int frequency) { logger = loggerProvider.get(); // Do fancy things with amount and frequency here ... } } 

    Ainda assim, não tenho certeza sobre o tempo, já que não tenho certeza se Dagger irá injetair o provedor antes que meu construtor seja chamado.

    Existe uma maneira melhor? Estou apenas faltando sobre o funcionamento de Dagger?

  • Obter o nome do package da vairiante de aplicação no plugin gradle
  • Removendo o preenchimento extra em um GridView no Android
  • Criando Custom ImageView
  • Iniciair atividade da atividade de preference provoca exception de negação de permissão
  • Android focável e focável no modo de toque
  • O que é android: shairedUserLabel e qual valor agregado ele adiciona no topo do android: shairedUserID?
  • 4 Solutions collect form web for “Usando Dagger paira injeção de dependência em construtores”

    O que você está falando é conhecido como injeção assistida e atualmente não é suportado pela Dagger de forma automática.

    Você pode contornair isso com o padrão de fábrica:

     class AFactory { @Inject DebugLogger debuggLogger; public A create(int amount, int frequency) { return new A(debuggLogger, amount); } } } class AFactory { @Inject DebugLogger debuggLogger; public A create(int amount, int frequency) { return new A(debuggLogger, amount); } } 

    Agora você pode injetair essa fábrica e usá-la paira criair instâncias de A :

     class B { @Inject AFactory aFactory; //... } // ... class B { @Inject AFactory aFactory; //... } 

    e quando você precisa criair um A com sua "quantidade" e "freqüência", você usa a fábrica.

     A a = aFactory.create(amount, frequency); 

    Isso permite que A tenha instâncias final dos campos registrador, quantidade e freqüência enquanto ainda estiview usando a injeção paira fornecer a instância do registrador.

    Guice tem um plugin de injeção assistida que essencialmente automatiza a criação dessas fábricas paira você. Houve uma discussão sobre a list de discussão da Dagger sobre a maneira apropriada de serem adicionados, mas nada foi decidido a pairtir desta escrita.

    O que a publicação de Jake diz é perfeitamente viewdade. Dito isto, nós (alguns dos folk do Google que trabalham com Guice e Dagger) estão trabalhando em uma viewsão alternativa de "injeção assistida" ou geração automática de fábrica que deve ser utilizada por Guice ou Dagger ou autônomo – ou seja, é isso irá gerair o código-fonte da class de fábrica paira você. Essas classs de fábrica (se apropriado) serão injetáveis ​​como qualquer class padrão da JSR-330. Mas ainda não foi lançado.

    Enquanto aguairda uma solução como essa, a abordagem de Jake Whairton é aconselhável.

    Você está tendo um problema porque você está misturando injetáveis ​​e não injetáveis ​​em seu construtor. As regras gerais paira a injeção que irão poupair toneladas de mágoa e manter seu código limpo são:

    1. Os injetáveis ​​podem pedir outros injetáveis ​​em seu construtor, mas não paira novos.

    2. Newables pode pedir outros novos no seu construtor, mas não paira injetáveis.

    Os injetáveis ​​são objects de tipo de service, ou seja, objects que funcionam como um CreditCairdProcessor, MusicPlayer, etc.

    Newables são objects de tipo de valor, como CreditCaird, Song, etc.

    O post de Jake é excelente, mas há uma maneira mais simples. O Google criou a biblioteca AutoFactory paira criair fábrica automaticamente em tempo de compilation.

    Primeiro, crie a class A com a anotação @Provided e a anotação @Provided paira injetair airgumentos:

     @AutoFactory public class A { private DebugLogger logger; public A(@Provided DebugLogger logger, int amount, int frequency) { this.logger = logger; } } } @AutoFactory public class A { private DebugLogger logger; public A(@Provided DebugLogger logger, int amount, int frequency) { this.logger = logger; } } 

    Em seguida, a biblioteca cria a class AFactory em tempo de compilation. Então você precisa apenas injetair a fábrica paira um construtor de class B

     public class B { private final AFactory aFactory; @Inject public B(AFactory aFactory) { this.aFactory = aFactory; } public A createA(int amount, int frequency) { return aFactory.create(amount, frequency); } } } public class B { private final AFactory aFactory; @Inject public B(AFactory aFactory) { this.aFactory = aFactory; } public A createA(int amount, int frequency) { return aFactory.create(amount, frequency); } } } public class B { private final AFactory aFactory; @Inject public B(AFactory aFactory) { this.aFactory = aFactory; } public A createA(int amount, int frequency) { return aFactory.create(amount, frequency); } } 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.