2016-11-22 9 views
13

Mam główną bibliotekę Android, w której definiuję reklamę CoreComponent przy użyciu zakresu @Singleton do wstrzykiwania instancji klas dostarczonych przez moduł podstawowy.Sztylet 2: Podaj to samo wystąpienie między wieloma komponentami z tym samym zakresem w różnych modułach bibliotecznych.

@Singleton 
@Component(modules = {CoreModule.class}) 
public interface CoreComponent { 
    void inject(SomeClass target); 
} 

@Module 
public class CodeModule { 
    @Singleton 
    @Provides 
    CoreRepository provideCoreRepository() { 
     return new CoreRepositoryImpl(); 
    } 
} 

Chciałbym dostęp do tych samych instancji @Singleton z innej biblioteki Android, który jest w zależności od biblioteki podstawowej i wykorzystuje inny komponent.

@Singleton 
@FooScope 
@Component(modules = {CoreModule.class, FooModule.class}) 
public interface FooComponent { 
    void inject(SomeActivity target); 
} 

public class FooActivity extends AppCompatActivity { 
    @Inject 
    public CoreRepository repo; 

    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) { 
     injectDependencies(); 
     super.onCreate(savedInstanceState); 
    } 
    [...] 
} 

Powyższy kod jest budowany, ale zakres @Singleton jest "lokalny" dla komponentu. Innymi słowy, istnieją dwie instancje singleton, jedna dla CoreComponent i jedna dla FooComponent.

Android Application 
├── Foo Library 
| └── Core Library 
├── Bar Library 
| └── Core Library 
· 
· 
· 
└── Core Library 

Myślę, że najlepszym rozwiązaniem powinno być przy użyciu podkomponent ale, niestety, nie wydaje się możliwe, ponieważ biblioteka Rdzeń ma widoczność innych bibliotek.

Czy istnieje inny sposób udostępnienia Sztyletowi tego samego wystąpienia jednej klasy między komponentami, jeśli klasa ma przypisany ten sam zakres?

+2

Pan spojrzał w zależności [Component] (http://stackoverflow.com/q/29587130/1426891) jeszcze? Zobacz [Javadoc] (https://google.github.io/dagger/api/latest/dagger/Component.html#component-dependencies) tutaj i zauważ, że możesz potrzebować jawnego ujawnienia kilku dodatkowych metod dostępowych w twoim CoreComponent, aby FooComponent może je wywoływać. –

+0

Zamówienie https://stackoverflow.com/questions/27036933/how-to-set-up-dagger-dependency-injection-from-scratch-in-android-project, które ma przykład użycia zakresów i zależnych komponentów. –

Odpowiedz

15

Usuń miejsca wstrzyknięcia ze swojego CoreComponent - ma teraz jedyną funkcję wystawiania wiązania dla CoreRepository do jego zależnych komponentów:

@Singleton 
@Component(modules = {CoreModule.class}) 
public interface CoreComponent { 
    CoreRepository coreRepository(); 
} 

Utwórz odniesienie do niniejszej jednoelementowy o zakresie komponentu wewnątrz aplikacji:

public class MyApplication extends Application { 
    private final CoreComponent coreComponent; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     coreComponent = DaggerCoreComponent 
          .coreModule(new CoreModule()) 
          .build(); 
    } 

    public static CoreComponent getCoreComponent(Context context) { 
     return ((MyApplication) context.getApplicationContext()).coreComponent; 
    } 
} 

Utwórz nowy węższy zakres:

@Scope 
@Retention(RetentionPolicy.RUNTIME) public @interface PerActivity {} 

Utwórz nowy komponent, który śledzi tego zakresu wraz z miejscami wstrzyknięcia chcesz:

@PerActivity 
@Component(dependencies = {CoreComponent.class}) 
public interface ActivityComponent { 
    void inject(FooActivity activity); 

    void inject(BarActivity activity); 
} 

Po wejściu do tego składnika działalność o zasięgu w miejscu wstrzyknięcia, trzeba będzie zapewnić wystąpienie CoreComponent do konstruktora . Teraz można wprowadzić do swojej Activity

public class FooActivity extends AppCompatActivity { 
     @Inject 
     public CoreRepository repo; 

     @Override 
     protected void onCreate(@Nullable Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      CoreComponent coreComponent = MyApplication.getCoreComponent(this); 
      DaggerActivityComponent.builder() 
       .coreComponent(coreComponent) 
       .build() 
       .inject(this); 
     } 
    } 
} 
+0

Hej dzięki dużo! Właśnie tego potrzebowałem! Jedyną rzeczą, którą robię inaczej, jest również utrzymywanie metod iniekcji w CoreComponent, ponieważ muszę również wstrzyknąć CoreRepository wewnątrz Core Library. Czy to nie jest miłe? Czy powinienem utworzyć nowy komponent z zależnością od niego do użycia w Bibliotece głównej i pozostawić CoreComponent bez iniekcji? –

+1

Zależnie od zakresu, jaki chcesz dla zależności w CoreLibrary. Jeśli chcesz tylko pojedynczych aplikacji, to prawdopodobnie jest w porządku. Jednak osobiście chciałbym mieć komponenty, które śledzą zakres swoich miejsc wstrzykiwań. –

+0

Jeszcze jedno pytanie: o ile mi wiadomo, nie mogę mieć więcej niż jednego zakresu zależności dla jednego komponentu, czy istnieje sposób na to, aby działał z wieloma zależnościami o określonym zakresie ?Na przykład mam wiele bibliotek, każda z komponentem z zakresem @Singleton i chciałbym móc współużytkować instancje singleton z moim ActivityComponent. Biblioteki są niezależne i nie widzą się nawzajem. –