Dagger 2 scope i subcomponents
Staram się, aby moja aplikacja była lepsza i Kod był łatwiejszy do utrzymania za pomocą Dagger2
wpadłem na ogólny pomysł, ale nadal nie mogę dowiedzieć się, jak zakresy są zarządzane przez Dagger2
Wstrzyknąłem sztylet do mojego projektu(brzmi zabawnie).
Stworzyłem komponent ApplicationComonent
i sprawdza się on doskonale w moim projekcie.
Oto Mój kod.
@Singleton
@Component(modules = {
ApplicationModule.class,
ThreadingModule.class,
NetworkModule.class,
DatabaseModule.class,
ServiceModule.class,
ParseModule.class,
PreferencesSessionModule.class})
public interface ApplicationComponent {
ActivityComponent activityComponent(ActivityModule activityModule);
void inject(BaseActivity baseActivity);
void inject(MainAppActivity mainAppActivity);
void inject(MyApplication application);
void inject(BaseFragment baseFragment);
void inject(MyService service);
void inject(RegistrationIntentService service);
}
Tworzę swoją instancję komponentu w klasie MyApplication
w ten sposób
private void initializeAndInjectComponent() {
mApplicationComponent =
DaggerApplicationComponent
.builder()
.threadingModule(new ThreadingModule(1))
.applicationModule(new ApplicationModule(this))
.networkModule(new NetworkModule(
MyService.API_SERVER_BASE_URL,
MyService.TIMEOUT))
.build();
mApplicationComponent.inject(this);
}
I mogę uzyskać składnik w celu wstrzyknięcia w moim Activities
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().inject(this);
Wszystko działa doskonale.
Aby dodać każdą metodę, a także klasę modułu jest adnotowana za pomocą @Singleton
scope, wszystkie moduły związane z ApplicationComponent
Teraz chcę ulepszyć zależności I widziałem wiele przykładów z niestandardowymi zakresami, takimi jak @PerActivity
, @PerFragment
. Mam wiele pytań, ale o to później.
Więc stworzyłem ActivityComponent
@PerActivity
@Subcomponent(
modules = {
NetworkServiceModule.class,
ActivityModule.class,
PermissionModule.class
})
public interface ActivityComponent {
Activity activity();
void inject(BaseActivity baseActivity);
}
Wszystkie moduły wyglądają tak
@PerActivity
@Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
this.mActivity = activity;
}
@Provides
@PerActivity
Activity provideActivity() {
return this.mActivity;
}
}
Mam następujące zależności w moim BaseActivity
// Dependencies from ApplicationComponent
@Inject
protected ApplicationSettingsManager mApplicationSettingsManager;
@Inject
protected ScheduledThreadPoolExecutor mPoolExecutor;
// Dependencies from ActivityComponent
@Inject
protected SpiceManager mSpiceManager;
@Inject
protected PermissionController mPermissionController;
I w mojej onCreate()
metodzie Wstrzykuję w następujący sposób
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().activityComponent(new ActivityModule(this)).inject(this);
Przed utworzeniem subkomponentu ActivityComponent
było to
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().inject(this);
Teraz mam błąd
Error:(34, 10) error: com.octo.android.robospice.SpiceManager cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
BaseActivity.mSpiceManager
[injected field of type: com.octo.android.robospice.SpiceManager mSpiceManager]
Nie wiem, gdzie jest problem, co przegapiłem.
Moje pytania dotyczące lunet w dagger2.
Wszystko oprócz @Singleton
jest ignorowane przez Dagger 2, mam rację ?
Nie rozumiem, jak zarządza się życiem komponentu ? Mam tylko jeden pomysł
Gdy używasz
@Singleton
adnotacja dagger tworzy obiekt w jakiejś puli statycznej które będą istniały podczas całego cyklu życia aplikacji i zostaną zniszczone, gdy instancja JVM (dalvik VM, ART)zostanie zniszczona.Gdy używasz innych adnotacji, tylko dla Ciebie jako programisty, aby lepiej zachować kod,
@PerActivity
,@PerFragment
to tylko niestandardowe adnotacje nic więcej. I jeśli umieścisz@PerFragment
komponent w klasie aplikacji, będzie on żył tak długo, jak długo będzie żył. Mam rację ?Więc rozumiem to w ten sposób, jeśli dagger znajdzie
@Singleton
adnotacja dodaje statyczne odniesienie do komponentu, gdy jest tworzony po raz pierwszy, a w przypadku jakiejkolwiek innej adnotacji nie zawiera odniesienia do komponentu.
Byłbym bardzo wdzięczny za każdą pomoc w problemach opisanych powyżej.
UPDATE
Dziękuję David Medenjak
za świetną odpowiedź, mam dużo lepsze zrozumienie Dagger2
.
Właśnie znalazłem problem, o ile używam osobnego komponentu Activity
, zapomniałem o dwie linie w ApplicationComponent
i zmiana inejction w moim MainActivity
na ActivityComponent
zamiast ApplicationComponent
, więc na pewno nie może rozwiązać zależności od subkomponentu.
void inject(BaseActivity baseActivity);
void inject(MainAppActivity mainAppActivity);
Teraz wszystko działa idealnie, Lubię {[10] } i oddzielną architekturę.
1 answers
Trochę radykalne, ale dla uproszczenia rzeczy:
wszystkie adnotacje dotyczące zakresu są niczym innym jak cukrem składniowym-w tym @Singleton
.
Zakresy najczęściej tylko sprawdzają czas kompilacji. Cykliczne zależności lub błędy dotyczące rzeczy, które mogły zostać pominięte. @Singleton
jest jak każdy inny zakres, jedyną różnicą jest to, że jest to już istniejąca adnotacja i nie musisz jej tworzyć samodzielnie. Możesz użyć @MySingleton
zamiast tego.
[...] dagger tworzy obiekt w część puli statycznej, która będzie istnieć podczas całego cyklu życia aplikacji
Nie. Dagger nie robi nic statycznego. Masz obiekty komponentowe. Komponenty te przechowują obiekty utworzone przez moduły. Jeśli obiekt w komponencie ma zakres komponentu, zostanie utworzony tylko raz w tego dokładnego komponentu. Jeśli zdecydujesz się utworzyć 2 Obiekty AppComponent
, będziesz miał 2 obiekty z każdego @Singleton
z adnotacją, każdy w jego składniku. Dlatego powinieneś zachowaj odniesienie do komponentu. Większość implementacji, które widziałem lub używałem, przechowuje AppComponent
w swoim Application
. Jeśli to zrobisz, możesz go użyć Jak singleton-to wciąż tylko POJO.
Tak. Jak już wspomniano powyżej, jest to tylko przedmiot. Zachowaj referencje, zachowaj obiekty. Wyrzucić lub utwórz nowy i masz nowe obiekty (zdefiniowane w tym komponencie / zakresie). Chociaż nie należy przechowywać komponenty o zasięgu aktywności lub fragmentu w dowolnym miejscu poza odpowiednio aktywnościami lub fragmentami, ponieważ przechowywanie ich np. w komponencie aplikacji najprawdopodobniej doprowadzi do wycieku pamięci. (Jeśli nie, prawdopodobnie nie potrzebowałbyś zakresu aktywności lub fragmentu.)[...] umieszczasz komponent @PerFragment w klasie aplikacji, który będzie żył tak długo, jak długo będzie żył.
Znowu nie. Nic statycznego. Zwykłe stare obiekty Javy. Możesz mieć wieleJeśli dagger znajdzie
@Singleton
adnotację, doda statyczne odniesienie do komponentu, gdy jest ona tworzona po raz pierwszy i w przypadku innych adnotacji nie będzie zawierała odniesienia do komponentu.
@Singleton
komponentów z własnymi obiektami, ale prawdopodobnie nie powinieneś (chociaż to sprawia, że testowanie oprzyrządowania jest możliwe / łatwe-po prostu zamień komponenty.)
Twój wspomniany błąd
SpiceManager nie może być dostarczony bez konstruktora @ Inject lub z @Provides - or @ Produces-adnotated method.
Oznacza to, że komponent, którym próbujesz wstrzyknąć obiekt, nie może znaleźć sposobu na wyprodukowanie lub dostarczenie SpiceManager
. Upewnij się, że dostarczasz go z AppComponent lub innego miejsca, nie brakuje żadnych adnotacji itp.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-02 11:48:42