Estou tentando entender os escopos no Dagger 2, especificamente o ciclo de vida dos gráficos com escopo. Como você cria um componente que será limpo quando você sair do escopo.
No caso de um aplicativo Android, usando o Dagger 1.x, geralmente você tem um escopo raiz no nível do aplicativo que estenderia para criar um escopo filho no nível da atividade.
public class MyActivity {
private ObjectGraph mGraph;
public void onCreate() {
mGraph = ((MyApp) getApplicationContext())
.getObjectGraph()
.plus(new ActivityModule())
.inject(this);
}
public void onDestroy() {
mGraph = null;
}
}
O escopo filho existia desde que você mantivesse uma referência a ele, que nesse caso era o ciclo de vida da sua Atividade. A eliminação da referência no onDestroy garantiu que o gráfico com escopo estivesse livre para ser coletado como lixo.
EDITAR
Jesse Wilson publicou recentemente um mea culpa
O Dagger 1.0 estragou muito seus nomes de escopo ... A anotação @Singleton é usada para gráficos raiz e gráficos personalizados, por isso é complicado descobrir qual é o escopo real de uma coisa.
e tudo o mais que li / ouvi apontou para o Dagger 2, melhorando a maneira como os escopos funcionam, mas estou lutando para entender a diferença. De acordo com o comentário de @Kirill Boyarshinov abaixo, o ciclo de vida de um componente ou dependência ainda é determinado, como sempre, por referências concretas. Então, a diferença entre os escopos Dagger 1.xe 2.0 é apenas uma questão de clareza semântica?
Meu entendimento
Adaga 1.x
Dependências eram @Singleton
ou não. Isso também se aplica às dependências no gráfico raiz e nos subgráficos, levando à ambiguidade em relação a qual gráfico a dependência estava vinculada (consulte No punhal, existem singletons no subgrafo em cache ou eles sempre serão recriados quando um novo subgráfico de atividade é construído? )
Dagger 2.0
Os escopos personalizados permitem criar escopos semanticamente claros, mas são funcionalmente equivalentes à aplicação @Singleton
no Dagger 1.x.
// Application level
@Singleton
@Component( modules = MyAppModule.class )
public interface MyAppComponent {
void inject(Application app);
}
@Module
public class MyAppModule {
@Singleton @Named("SingletonScope") @Provides
StringBuilder provideStringBuilderSingletonScope() {
return new StringBuilder("App");
}
}
// Our custom scope
@Scope public @interface PerActivity {}
// Activity level
@PerActivty
@Component(
dependencies = MyAppComponent.class,
modules = MyActivityModule.class
)
public interface MyActivityComponent {
void inject(Activity activity);
}
@Module
public class MyActivityModule {
@PerActivity @Named("ActivityScope") @Provides
StringBuilder provideStringBuilderActivityScope() {
return new StringBuilder("Activity");
}
@Name("Unscoped") @Provides
StringBuilder provideStringBuilderUnscoped() {
return new StringBuilder("Unscoped");
}
}
// Finally, a sample Activity which gets injected
public class MyActivity {
private MyActivityComponent component;
@Inject @Named("AppScope")
StringBuilder appScope
@Inject @Named("ActivityScope")
StringBuilder activityScope1
@Inject @Named("ActivityScope")
StringBuilder activityScope2
@Inject @Named("Unscoped")
StringBuilder unscoped1
@Inject @Named("Unscoped")
StringBuilder unscoped2
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
appScope.append(" > Activity")
appScope.build() // output matches "App (> Activity)+"
activityScope1.append("123")
activityScope1.build() // output: "Activity123"
activityScope2.append("456")
activityScope1.build() // output: "Activity123456"
unscoped1.append("123")
unscoped1.build() // output: "Unscoped123"
unscoped2.append("456")
unscoped2.build() // output: "Unscoped456"
}
public void onDestroy() {
component = null;
}
}
O argumento é que o uso @PerActivity
comunica sua intenção com relação ao ciclo de vida desse componente, mas, em última análise, você pode usá-lo em qualquer lugar / a qualquer momento. A única promessa de Dagger é que, para um determinado componente, os métodos anotados por escopo retornem uma única instância. Suponho também que o Dagger 2 use a anotação de escopo no componente para verificar se os módulos fornecem apenas dependências que estão no mesmo escopo ou sem escopo.
Em suma
As dependências ainda são singleton ou não singleton, mas @Singleton
agora são destinadas a instâncias singleton no nível do aplicativo e escopos personalizados são o método preferido para anotar dependências singleton com um ciclo de vida mais curto.
O desenvolvedor é responsável por gerenciar o ciclo de vida dos componentes / dependências eliminando referências que não são mais necessárias e responsável por garantir que os componentes sejam criados apenas uma vez no escopo a que se destinam, mas as anotações de escopo personalizadas facilitam a identificação desse escopo .
A pergunta de US $ 64 mil *
O meu entendimento dos escopos e ciclos de vida do Dagger 2 está correto?
* Na verdade, não é uma pergunta de US $ 64.000.
plus()
referência a novo gráfico, foi armazenado em Activity e vinculado ao seu ciclo de vida (sem referência emonDestroy
). Quanto aos escopos, eles garantem que suas implementações de componentes sejam geradas sem erros no tempo de compilação, com todas as dependências satisfeitas. Portanto, não apenas para fins de documentação. Confira alguns exemplos deste tópico .