Только сегодня начал использовать Dagger 2, и я немного не понимаю, как именно мне все это нужно настроить.

Я пытаюсь ввести POJO, но он всегда равен нулю. Для начала немного кода:

App.java

private AppComponent appComponent;

@Override
public void onCreate() {
    super.onCreate();
    appComponent = DaggerAppComponent
            .builder()
            .appModule(new AppModule(this))
            .build();
}

public AppComponent component() {
    return appComponent;
}

AppModule.java

@Module
public class AppModule {
    private Application app;

    public AppModule(Application app) {
        this.app = app;
    }

    @Provides @Singleton
    public Application application() {
        return app;
    }
}

AppComponent.java

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App application);
    Application application();
}

NetworkingManager.java

@Singleton
public class NetworkingManager {
    private Context ctx;

    @Inject
    public NetworkingManager(Context context) {
        this.ctx = context;
    }
}

NetModule.java

@Module
public class NetModule {
    @Provides @Singleton
    public NetworkingManager provideNetworkingManager(Application application) {
        return new NetworkingManager(application);
    }
}

NetComponent.java

@Singleton
@Component(modules = {NetModule.class},
        dependencies = {AppModule.class})
public interface NetComponent {
    void inject(NetworkingManager networkingManager);
}

SomeClass.java

@Inject
NetworkingManager networkingManager;

public void doSomethingWithNetworkManager() {
    networkManager.doStuff();
}

Я потратил много времени, просматривая множество руководств, вопросов и примеров, но так и не смог понять, что я делаю не так.

Я на 99% уверен, что что-то неправильно настроил, но я не мог понять, что именно.

6
Jordan 30 Май 2015 в 02:50
Похоже, вы немного запутались. Какова твоя цель? Где вы пытаетесь использовать NetworkingManager?
 – 
Emmanuel
30 Май 2015 в 03:03
NetworkManager в настоящее время является одноэлементным. Он обрабатывает все асинхронные сети. Его используют повсюду. Моя цель - устранить синглтон и переключиться на DI, а также сделать класс тестируемым.
 – 
Jordan
30 Май 2015 в 04:19

1 ответ

Лучший ответ

Основываясь на вашем комментарии, вы хотите, чтобы NetworkingManager был доступен везде в вашем приложении.

Начнем с вашего определения Component:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App application);
}

Это сообщает Dagger, что этот компонент будет внедрять класс App. Теперь здесь вы также можете указать Dagger другие классы, которые вы хотите внедрить. Итак, если вы хотите также ввести, например, Activity, вы должны добавить:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(App application);
    void inject(MainActivity activity) //Where MainActivity is a class that extends Activity.
}

Обратите внимание, что это не лучший способ, IMO, разделять зависимости приложения; вам следует создать Component, который унаследован от AppComponent, и сделать так, чтобы AppComponent открывал желаемые общие зависимости.

Теперь посмотрим на ваш класс модуля:

@Module
public class NetModule {
    @Provides @Singleton
    public NetworkingManager provideNetworkingManager(Application application) {
        return new NetworkingManager(application);
    }
}

Вот вы @Provide используете NetworkingManager, это нормально. Ваш NetworkingManager требует Application (на самом деле Context), почему бы не предоставить App внутри NetworkingManager? Или, что еще лучше, почему бы не предоставить NetworkingManager внутри AppModule, поскольку AppModule должны @Provide вещи, общие для всего Application:

@Module
public class AppModule {
    private Application app;

    public AppModule(Application app) {
        this.app = app;
    }

    @Provides @Singleton
    public Application application() {
        return app;
    }

    @Provides @Singleton
    public NetworkingManager provideNetworkingManager(Application application) {
        return new NetworkingManager(application);
    }
}

Теперь внутри вашего класса App:

public class App extends Application {
    private AppComponent appComponent;

@Override
public void onCreate() {
    super.onCreate();
    appComponent = DaggerAppComponent
            .builder()
            .appModule(new AppModule(this))
            .build();
   appComponent.inject(this);
}

public AppComponent component() {
    return appComponent;
 }
}

И в нашем гипотетическом MainActivity:

public class MainActivity extends Activity {

private AppComponent appComponent;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    appComponent = ((App)getApplicationContext()).getAppComponent();
    appComponent.inject(this);
   }
 }

Похоже, вы неправильно используете @Component(dependencies = {...}). dependencies используется, когда вы хотите показать зависимость от одного Component к другому с помощью механизма, о котором я упоминал выше.

10
Cam 28 Сен 2016 в 21:29
Хорошо, в этом есть немного больше смысла. 1) Я предполагаю, что в App.onCreate() вы имели в виду .build(), а не .inject(this), поскольку inject() возвращает недействительность. 2) NetworkingManager находится в другом пакете, чем App. Я подумал, что было бы лучше сохранить отдельные модули для каждого пакета. Разве это невозможно? 3) Получение AppComponent в MainActivity.onCreate() нормально для действий и фрагментов. А как насчет POJO, у которых нет доступа к контексту приложения? Должен ли я сначала получить контекст действия и передать его в POJO? Это кажется обратным к точке DI с Dagger.
 – 
Jordan
30 Май 2015 в 16:19
1) Вы правы, я исправил код App. Вы бы позвонили inject(), если хотите также ввести App. 2) У вас определенно могут быть разные модули для каждого пакета, но я думаю, что имеет смысл иметь разные модули для каждой области (уровень приложения, уровень активности и т. Д.). 3) Для POJO вы можете просто аннотировать их конструктор с помощью @Inject, если они используются из класса, который уже был введен Component. Это может сбивать с толку. Мы можем поговорить об этом подробнее, если хотите, в чате.
 – 
Emmanuel
30 Май 2015 в 16:29