Skocz do zawartości
pionas

Dagger jak to ugryźć?

    Rekomendowane odpowiedzi

    pionas

    Hej,

     

    próbuję wgryźć się w Dagger'a.

    Czytałem na http://www.holdapp.com/pl/blog/android-small-talks-wstrzykiwanie-zaleznosci-poprzez-daggera-2 i nie jestem pewien czy to dobrze rozumiem...

     

    Obowiązkowo muszę stworzyć własną klasę dziedziczącą po Application, która będzie wyglądała mniej więcej tak:

    public class App extends Application {
    
        private ApplicationComponent applicationComponent;
        
        public ApplicationComponent getComponent() {
            if (applicationComponent == null) {
                applicationComponent = DaggerApplicationComponent.builder()
                        .applicationModule(new ApplicationModule(this))
                        .build();
            }
            return applicationComponent;
        }
    }

     

    Do tego musimy stworzyć ApplicationModule np:

    @Module
    public class ApplicationModule {
        protected final Application application;
     
        public ApplicationModule(Application application) {
            this.application = application;
        }
     
        @Provides
        Application provideApplication() {
            return application;
        }
     
        @Provides
        Context provideContext() {
            return application;
        }
    }

    Czyli zawsze będziemy wstrzykiwali Context i Application?

     

    @Singleton
    @Component(modules = {ApplicationModule.class})
    public interface ApplicationComponent {
        void inject(MainActivity target);
    }

    To oznacza że tworzymy połączenie pomiędzy MainActivity a ApplicationModule wywołując to w taki sposób:

    ((App) getApplication()).getComponent().inject(this);

     

    Jakbym chciał w MainActivity dołączyć Adapter (MyItemRecyclerViewAdapter) to co musiałbym zrobić?

    W ApplicationComponent muszę dodać kolejny moduł? MyItemRecyclerViewModule.class a w nim:

    @Module
    public class MyItemRecyclerViewModule {
    
        @Singleton
        @Provides
        public MyItemRecyclerViewAdapter provideRepo(List<DummyItem> items, OnListFragmentInteractionListener listener) {
            return new MyItemRecyclerViewAdapter(items, listener);
        }
    
    }

    i w MainActivity muszę zadeklarować:

    @Inject MyItemRecyclerViewAdapter myItemRecyclerViewAdapter;

    tylko jak przekazać List<DummyItem> i OnListFragmentInteractionListener?

    Czy wystarczy że zadeklaruję np:

    private OnListFragmentInteractionListener mListener;
    private List<DummyItem> items;

    ??

     

    Dzięki za zrozumienie tego ;)

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Coderoid
    Godzinę temu, pionas napisał:

    Czyli zawsze będziemy wstrzykiwali Context i Application?

     

    Nie, jeśli nie potrzebujesz contextu to go tam nie dajesz.

     

    Godzinę temu, pionas napisał:

    Jakbym chciał w MainActivity dołączyć Adapter (MyItemRecyclerViewAdapter) to co musiałbym zrobić?

    Czysto teoretycznie, możesz stworzyć nowy moduł, możesz skorzystać z istniejącego. Z praktycznego punktu widzenia tego się nie robi. Jak poużywasz dagger'a to zobaczysz że nie wszystko powinno być wstrzykiwane. 

     

    Godzinę temu, pionas napisał:

    tylko jak przekazać List<DummyItem> i OnListFragmentInteractionListener?

     

    I to jest jeden przypadek gdzie dowiadujesz się, że tego się nie robi, bo te obiekty również powinny być dostarczane przez daggera.

     

    Ogólnie Twoje podejście do tego jest dobre i prawidłowe. Kwestia używania tego i ogarnięcia co i jak. 

     

    Z dobrej rady: Warto się zastanowić nad tym aby nie nadużywać @Singleton 

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    pionas
    18 minut temu, Coderoid napisał:

    I to jest jeden przypadek gdzie dowiadujesz się, że tego się nie robi, bo te obiekty również powinny być dostarczane przez daggera.

    Czyli powinienem przerobić MyItemRecyclerViewModule na coś takiego:

    @Module
    public class MyItemRecyclerViewModule {
        @Provides
        public OnListFragmentInteractionListener getListener() {
            return new OnItemsListListener(); // implements OnListFragmentInteractionListener
        }
        @Provides
        public List<DummyItem> getItems() {
            return new DummyItemsRepository().getItems();
        }
        @Singleton
        @Provides
        public MyItemRecyclerViewAdapter provideRepo(OnListFragmentInteractionListener listener) {
            return new MyItemRecyclerViewAdapter(getItems(), getListener());
        }
    
    }

    jak przekazać Context? coś takiego:

    @Module
    public class MyItemRecyclerViewModule {
        @Provides
        public OnListFragmentInteractionListener getListener() {
            return new OnItemsListListener(); // implements OnListFragmentInteractionListener
        }
        @Provides
        public List<DummyItem> getItems(Context context) {
            return new DummyItemsRepository(context).getItems();
        }
        @Singleton
        @Provides
        public MyItemRecyclerViewAdapter provideRepo(OnListFragmentInteractionListener listener) {
            return new MyItemRecyclerViewAdapter(getItems(), getListener());
        }
    
    }

    Czy zamiast Context context powinienem dać: provideContext() ?? tj:

    @Module
    public class MyItemRecyclerViewModule {
        @Provides
        public OnListFragmentInteractionListener getListener() {
            return new OnItemsListListener(); // implements OnListFragmentInteractionListener
        }
        @Provides
        public List<DummyItem> getItems() {
            return new DummyItemsRepository(prodiveContext()).getItems();
        }
        @Singleton
        @Provides
        public MyItemRecyclerViewAdapter provideRepo(OnListFragmentInteractionListener listener) {
            return new MyItemRecyclerViewAdapter(getItems(), getListener());
        }
    
    }

     

    czy nazwy metod dla adnotacji @Provides muszą mieć przedrostek provide?

    Jeśli chcę wstrzyknąć we fragmencie to mogę do interfejsu ApplicationComponent dodać:

    void inject (MyFragment fragment);


    czy muszę stworzyć nowy komponent?

     

    25 minut temu, Coderoid napisał:

    Ogólnie Twoje podejście do tego jest dobre i prawidłowe. Kwestia używania tego i ogarnięcia co i jak. 

    czyli zamiast pytać warto zabrać się do pisania i analizowania? ;)

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Coderoid
    30 minut temu, pionas napisał:

    Czyli powinienem przerobić MyItemRecyclerViewModule na coś takiego:

    Tak jak pisałem, teoretycznie tak, praktycznie nie rób tego. 

    30 minut temu, pionas napisał:

    jak przekazać Context? coś takiego:  

    Normalnie, przez konstruktor i w Injectorze zabierzesz sobie Application (application też jest contextem)

    30 minut temu, pionas napisał:

    czy nazwy metod dla adnotacji @Provides muszą mieć przedrostek provide?

    Nie muszą, ale dobrze jest to dawać. Możesz sobie wymyślić inny przedrostek. To jest nazwa metody i powinna zawierać nazwę taką, która mówi o tym co metoda robi. 

    30 minut temu, pionas napisał:

    Jeśli chcę wstrzyknąć we fragmencie to mogę do interfejsu ApplicationComponent dodać:

    Możesz. Są jeszcze opcje typu PerActivity, PerFragment. Wszystko zależy od tego jak chcesz zarządzać wstrzykiwanymi obiektami i jak długo mają żyć.

    30 minut temu, pionas napisał:

    czyli zamiast pytać warto zabrać się do pisania i analizowania? ;)

    No pewnie!

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    pionas
    11 minut temu, Coderoid napisał:

    Tak jak pisałem, teoretycznie tak, praktycznie nie rób tego.

    czyli Adapter zrobić w Activity tj. adapter = new MyItemRecyclerViewAdapter(getContext())?

     

    11 minut temu, Coderoid napisał:

    Normalnie, przez konstruktor i w Injectorze zabierzesz sobie Application (application też jest contextem)

    i zgłupiałem, możesz podać jakiś przykład? ;)

     

     

    [EDIT]

    Żeby znów nie pytać.

    Jeśli do adapterów nie ma sensu używać Daggera to do czego warto go używać?

    Edytowane przez pionas

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Coderoid
    @Module
    public class AppModule {
    
        private Application application;
    
        public AppModule(Application application) {
            this.application = application;
        }
    }

     

    25 minut temu, pionas napisał:

    czyli Adapter zrobić w Activity tj. adapter = new MyItemRecyclerViewAdapter(getContext())?

     

    Tak, adaptery rób normalnie w activity, a nie przez Dagger'a. Jeśli ktoś inny ma inne zdanie, chętnie posłucham argumentów. Ale ja nie jestem zwolennikiem wstrzykiwania "wszystkiego".

     

    26 minut temu, pionas napisał:

    Jeśli do adapterów nie ma sensu używać Daggera to do czego warto go używać?

    Ja używam do: Presenterów, Service (dostarczających dane do prezentera), klasy statyczne które są np jakimiś konwerterami danych, możesz w niektórych przykładach znaleźć coś takiego jak NetworkModule i z tego też korzystam. 

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    pionas

    Jak już mowa o Presenter znalazłem na dysku przykład:

    Na dysku znalazłem przykład z Presenterem

    W MainActivity jest coś takiego:
     

        @Inject
        ActivityMVP.Presenter presenter;

    w onCreate jest:
     

    ((App) getApplication()).getComponent().inject(this);

    MainActivity implementuje ActivityMVP.View

    public interface ActivityMVP {
        interface View {
            void updateData(ViewModel viewModel);
            void showSnackbar(String s);
        }
    
        interface Presenter {
            void loadData();
        }
    
        interface Model {
            void result();
        }
    }

    w ApplicationComponent dodany jest AcitivyModule.class a w nim:
     

    @Module
    public class ActivityModule {
    
        @Provides
        public ActivityMVP.Presenter provideActivityPresenter(ActivityMVP.Model model) {
            return new ActivityPresenter(model);
        }
    
        @Provides
        public ActivityMVP.Model provideActivityModel(Repository repository) {
            return new ActivityModel(repository);
        }
    
        @Singleton
        @Provides
        public Repository provideRepo() {
            return new ActivityRepository();
        }
    }

    ActivityPresenter wygląda tak:

    public class ActivityPresenter implements ActivityMVP.Presenter {
    
        private ActivityMVP.View view;
        private ActivityMVP.Model model;
    
        public ActivityPresenter(ActivityMVP.Model model) {
            this.model = model;
        }
    
        @Override
        public void loadData() {
    		model.result().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<ViewModel>() {
                @Override
                public void onCompleted() {
    
                }
    
                @Override
                public void onError(Throwable e) {
                    e.printStackTrace();
                    if (view != null) {
                        view.showSnackbar("Error getting");
                    }
                }
    
                @Override
                public void onNext(ViewModel viewModel) {
                    if (view != null) {
                        view.updateData(viewModel);
                    }
                }
            });
        }
    }

    Skąd Dagger wiedział że do provideActivityModel ma dać new ActivityRepository(), a do provideActivityPresenter new ActivityModel(repository)?

    Czy jeśli podepnę do applicationComponent kolejny Moduł, a będzie różnił się jedynie provideActivityModel bo będzie np. new ActivityModel2 to jak Dagger to rozpozna?

     

    A co gdybym w ActivityModule usunął provideRepo lub prodiveActivityModel?

    Edytowane przez pionas

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Coderoid

    Jeśli popatrzysz na klasy generowane przez daggera, to zobaczysz w jaki sposób dagger wie co i gdzie wstrzyknąć :)

    • Lubię to! 1

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    pionas

    Aha, czyli coś na zasadzie tak ma być? ;)

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    Coderoid

    Raczej, to tak działa i ma to sens :)

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

    Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

    Zarejestruj nowe konto

    Załóż nowe konto. To bardzo proste!

    Zarejestruj się

    Zaloguj się

    Posiadasz już konto? Zaloguj się poniżej.

    Zaloguj się

    • Ostatnio przeglądający   0 użytkowników

      Brak zarejestrowanych użytkowników przeglądających tę stronę.

    x