Android автоинъекция модулей кинжала на каждый из которых мне нужно - PullRequest
0 голосов
/ 14 апреля 2019

После успешной реализации Dagger в проекте я должен указать кинжал для каждого класса, который я хочу использовать, и добавить модули, например RestClient из retrofit, я хочу знать, есть ли способ автоматически определить components вклассы?

например моя реализация:

public class CoreApplication extends MultiDexApplication {
    private static ProjectApplicationComponent component;
    private RestClient restClient;
    private Picasso picasso;
    private Handler handler;

    @Override
    public void onCreate() {
        super.onCreate();

        ...
        component = DaggerProjectApplicationComponent.builder()
                .contextModule(new ContextModule(this))
                .networkServiceModule(new NetworkServiceModule(ClientSettings.SERVER_URL))
                .build();

        restClient= component.apiService();
        picasso = component.getPicasso();
        handler = component.getHandler();
    }

    public static ProjectApplicationComponent getComponent() {
        return component;
    }
}

и мой ApplicationComponent, который я определяю классом ведьмы или действием или фрагментом, который я хочу внедрить в модули:

@ActivitiesScope
@Component(dependencies = ProjectApplicationComponent.class)
public interface ApplicationComponent {
    void inject(PersonsRemoteRepository personsRemoteRepository);
}

и PersonsRemoteRepository класс, который я хочу внедрить RestClient, чтобы использовать Retrofit

public class PersonsRemoteRepository implements PersonsRepository {
    @Inject
    private RestClient restClient;

    private final ApplicationComponent component;

    public PersonsRemoteRepository() {
        component = DaggerApplicationComponent.builder()
                .projectApplicationComponent(CoreApplication.getComponent())
                .build();

        component.inject(this);
    }

    ...
}

мой RestClient класс:

public interface RestClient {
    @Headers("Content-Type: application/json")
    @POST("/api/v1/getPersons")
    Observable<List<Person>> getPersons();
}

мое значение удаляет componentи component.inject(this); из всех классов, которые я хочу внедрить RestClient

@Inject
private RestClient restClient;

например, упрощенный PersonsRemoteRepository класс должен быть:

public class PersonsRemoteRepository implements PersonsRepository {
    @Inject
    private RestClient restClient;

    public PersonsRemoteRepository() {

    }

    ...
}

Заранее спасибо


ОБНОВЛЕНИЕ ПОЧТЫ

в этой моей деятельности inject(this) недоступно в этой строке кода:

CoreApplication.getComponent().inject(this);

Моя деятельность:

public class LoginActivity extends AppCompatActivity{
    @Inject
    PersonsRemoteRepository personsRemoteRepository;

    @Inject
    RestClient restClient;

    private LoginActivityBinding mBinding;
    private LoginMethodsToPageViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        CoreApplication.getComponent().inject(this);

        mBinding = DataBindingUtil.setContentView(this, R.layout.login_activity);

        personsRemoteRepository = new PersonsRemoteRepository(restClient);
        viewModel = new LoginMethodsToPageViewModel(personsRemoteRepository, this, mBinding);
        mBinding.setViewModel(viewModel);
    }

    ...
}

на этом снимке экрана, как вы видите, у меня нет inject() метода

enter image description here

PersonsRemoteRepository классс после изменения:

public class PersonsRemoteRepository implements PersonsRepository {
    private RestClient restClient;

    @Inject
    PersonsRemoteRepository(RestClient restClient) {
        this.restClient = restClient;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Observable<List<Person>> getAllPersons() {
        Observable<List<Person>> observable = restClient.getPersons();

        return observable
                .flatMap((Function<List<Person>, Observable<List<Person>>>) Observable::fromArray);
    }
}

Ответы [ 2 ]

1 голос
/ 14 апреля 2019

Есть два вопроса, как вводить в CoreApplication и как вводить в действия. И есть два соответствующих компонента, ProjectApplicationComponent и ApplicationComponent, связанных зависимостью компонента.


Ввести в приложение, ответ от Густаво полезен:

  • Аннотировать поля CoreApplication как @Inject,
  • Заменить методы предоставления в ProjectApplicationComponent на метод ввода членов:

    @ApplicationScope
    @Component(
            modules = {
                ContextModule.class,
                NetworkServiceModule.class,
                ...,
            })
    public interface ProjectApplicationComponent {
        // Members-injection method
        void inject(CoreApplication coreApplication);
    }
    
  • Создайте ProjectApplicationComponent и вызовите метод inject:

    // CoreApplication.onCreate
    component =
        DaggerProjectApplicationComponent.builder()
            .contextModule(new ContextModule(this))
            .networkServiceModule(...)
            .build();
    component.inject(/* coreApplication= */ this);
    

Чтобы ввести в LoginActivity, у зависимого ApplicationComponent должен быть метод ввода членов:

@ActivitiesScope
@Component(dependencies = ProjectApplicationComponent.class)
public interface ApplicationComponent {
    void inject(LoginActivity loginActivity);
}

Напомним, что у вашего LoginActivity есть два @Inject редактируемых поля с типами RestClient и PersonsRemoteRepository.

public class LoginActivity extends AppCompatActivity {
    @Inject PersonsRemoteRepository personsRemoteRepository;
    @Inject RestClient restClient;
}

Чтобы зависимый ApplicationComponent получил RestClient, зависимый ProjectApplicationComponent должен предоставить метод обеспечения:

@ApplicationScope
@Component(modules = {...})
public interface ProjectApplicationComponent {
    // Members-injection method
    void inject(CoreApplication coreApplication);

    // Provision method
    RestClient getRestClient();
}

Для PersonsRemoteRepository, Dagger может создать его, используя инжектор конструктора:

// May be scoped @ActivitiesScope, or not
public class PersonsRemoteRepository implements PersonsRepository {
    private final RestClient restClient;

    @Inject
    PersonsRemoteRepository(RestClient restClient) {
        this.restClient = restClient;
    }
}

Затем, когда вы создаете LoginActivity, создайте созданный Dagger компонент следующим образом:

// LoginActivity.onCreate
ApplicationComponent component =
    DaggerApplicationComponent.builder()
        .projectApplicationComponent(CoreApplication.getComponent())
        .build();
component.inject(/* loginActivity= */ this);
1 голос
/ 14 апреля 2019

Вам не нужно создавать свой компонент для каждого класса, в который вы хотите внедрить зависимости. Зависимости могут быть предоставлены через конструктор, помеченный @Inject:

public class PersonsRemoteRepository implements PersonsRepository {

    private RestClient restClient;

    @Inject
    public PersonsRemoteRepository(RestClient restClient) {
         this.restClient = restClient;
    }
}

И любой другой класс, которому нужен этот репозиторий, может сделать то же самое:

public class AnyOtherClass {
    private PersonsRemoteRepository personsRemoteRepository;

    @Inject
    public AnyOtherClass(PersonsRemoteRepository personsRemoteRepository) {
        this.personsRemoteRepository = personsRemoteRepository;
    }

Вам нужно использовать component.inject только для классов, экземпляры которых создаются Android, таких как «Приложение», «Действия» и «Фрагменты».

public class MyActivity {
    @Inject PersonsRemoteRepository personsRemoteRepository;

    @Override
    public void onCreate() {
        super.onCreate();

        CoreApplication.getComponent().inject(this);
    }
}

Изменения, необходимые в вашем CoreApplication:

public class CoreApplication extends MultiDexApplication {
    private static ProjectApplicationComponent component;

    @Inject private RestClient restClient;
    @Inject private Picasso picasso;
    @Inject private Handler handler;

    @Override
    public void onCreate() {
        super.onCreate();

        ...
        component = DaggerProjectApplicationComponent.builder()
                .contextModule(new ContextModule(this))
                .networkServiceModule(new NetworkServiceModule(ClientSettings.SERVER_URL))
                .build();

        component.inject(this);
    }
}

Изменения, необходимые в вашем ApplicationComponent:

@ActivitiesScope
@Component(dependencies = ProjectApplicationComponent.class)
public interface ApplicationComponent {
    void inject(CoreApplication coreApplication);

    void inject(MyActivity myActivity);
}
...