Dagger2 + URL изменения дооснащения с помощью подкомпонента: невозможно предоставить без аннотированного @ Provides- или @ Produces-метода - PullRequest
1 голос
/ 04 февраля 2020

Я новичок ie в Dagger. Я использовал этот ответ , чтобы изменить URL во время выполнения.

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

примечание: у меня есть буксирные компоненты (ApplicationComponent,ActivityComponent) и один субкомпонент (UrlComponent). В дополнение я использую @Singletone, @PerUrl и @PerActivty в качестве области видимости.

Когда я хочу Inject RestApi в каждом действии, я сталкиваюсь с этой ошибкой:

 error: com.example.testdagger2.RestApi cannot be provided without an @Provides- or @Produces-annotated method.
com.example.dagger2.RestApi is injected at
com.example.dagger2.RestApiHelper.restApi
com.example.dagger2.RestApiHelper is injected at
com.example.dagger2.MainActivity.restApiHelper
com.example.testdagger2.MainActivity is injected at
com.example.testdagger2.di.component.ActivityComponent.inject(mainActivity)

Прежде чем мне пришлось изменить URL-адрес в среде выполнения, у меня было два компонента и модули (appCompoent и activtyComponent), и все провайдеры (такие как Retrofit и RestApi, ...) были в ApplicationModule, и программа работала нормально.

ApplicationComponent. java

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    void inject(ExampleApplication exampleApplication);

    @ApplicationContext
    Context context();

    Application application();

    UrlComponent plus(UrlModule component);
}

ApplicationModule. java

@Module
public class ApplicationModule {

    private Application mApplication;

    public ApplicationModule(Application application) {
        this.mApplication = application;
    }

        @Provides
        @ApplicationContext
        Context provideContext() {
            return mApplication;
        }

        @Provides
        Application provideApplication() {
            return mApplication;
        }
    }

UrlComponent. java

@PerUrl
@Subcomponent(modules = UrlModule.class)
public interface UrlComponent {

}

UrlModule. java

@Module
public class UrlModule {
    private String url;

    public UrlModule(String url) {
        this.url = url;
    }

    @Provides
    @PerUrl
    OkHttpClient provideOkhttpClient() {
        return new OkHttpClient.Builder()
                .connectTimeout(20, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();
    }

    @Provides
    @PerUrl
    Retrofit provideRetrofit(String baseURL, OkHttpClient client) {

        return new Retrofit.Builder()
                .baseUrl(baseURL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();
    }

    @Provides
    RestApiHelper provideRestApiHelper(RestApiHelper restApiManager) {
        return restApiManager;
    }

    @Provides
    public RestApi provideApiService() {
        return provideRetrofit(url, provideOkhttpClient())
                .create(RestApi.class);

    }
}

ActivityComponent. java

@PerActivity
@Component(modules = ActivityModule.class,dependencies = ApplicationComponent.class)
public interface ActivityComponent {

    void inject(MainActivity mainActivity);
  .
  .
  .

}

ActivityModule. java

@Module
public class ActivityModule {

    private AppCompatActivity mActivity;

    public ActivityModule(AppCompatActivity mActivity) {
        this.mActivity = mActivity;
    }


    @Provides
    @ActivityContext
    Context provideContext() {
        return mActivity;
    }

    @Provides
    AppCompatActivity provideActivity() {
        return mActivity;
    }

   .
   .
   .

}

RestApi. java

public interface RestApi {

    Single<Object> getquestionlist(@Query("page") int page);

    Single<Object> getCategoryList();
}

RestApiHelper. java

public class RestApiHelper implements RestApi {

    @Inject
    RestApi restApi;

    @Inject
    public RestApiHelper(RestApi restApi) {
        this.restApi = restApi;
    }

    @Override
    public Single<Object> getquestionlist(int page) {
        return restApi.getquestionlist(1);
    }

    @Override
    public Single<Object> getCategoryList() {
        return restApi.getCategoryList();
    }

Пример приложения. java

public class ExampleApplication extends Application {


    @Inject
    ApplicationComponent appComponent;


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

        appComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this)).build();
        appComponent.inject(this);
        appComponent.plus(new UrlModule("www/test/en"));


    }

    public ApplicationComponent getAppComponent() {
        return appComponent;
    }


}

BaseActivity. java

public class BaseActivity extends AppCompatActivity {


    ActivityComponent activityComponent;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //activityComponent=DaggerActivityComponent.builder().applicationModule()

        activityComponent= DaggerActivityComponent.builder()
                .applicationComponent(((ExampleApplication)getApplication()).getAppComponent())
                .build();

    }

    public ActivityComponent getActivityComponent() {
        return activityComponent;
    }
}

MainActivity.jaqva

public class MainActivity extends BaseActivity {


    @Inject
    RestApiHelper restApiHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


    ActivityComponent component= getActivityComponent();
    component.inject(this);

        restApiHelper.getquestionlist(1).subscribe(new Consumer<Object>() {
        @Override
        public void accept(Object o) throws Exception {

        }
    });

Теперь у меня есть вопросы о буксировке:

1-дел. Не все провайдеры, встроенные в Urlmodule, могут быть добавлены к ApplicationModule (UrlModule is Subcomepoent of the ApplicationComponent)

 @PerActivity
    @Component(modules = ActivityModule.class,dependencies = ApplicationComponent.class)
    public interface ActivityComponent {

, и поскольку ApplicationComponent является зависимостями ActivityComponent, все эти Providers можно использовать в Компонент Activity также?

2-И как базовый c вопрос, в чем проблема?

Ответы [ 2 ]

2 голосов
/ 07 февраля 2020

Если все провайдеры, встроенные в модуль UrlModule, не будут добавлены в ApplicationModule (UrlModule является подкомпонентом ApplicationComponent)

Когда вы объявляете зависимость компонента, то зависимый компонент может использовать только открытые зависимости, которые объявлены внутри класса компонента dependencies, в вашем случае это context и application в вашем классе ApplicationComponent и предоставлены ApplicationModule.

Для проверки (тестирования ):

1) Добавить новые предложения в модуль приложения

// inside ApplicationModule
@Provides
Student getNum() {
    return new Student("aa");
}

2) Создать и использовать объект ActivityComponent для внедрения Student в любой класс. Это приведет к отсутствию обеспечения. Это можно исправить, выставив Student в ApplicationComponent классе как:

Student getStu();

2-И как базовый c вопрос, где проблема?

Со следующими реализациями:

  1. График зависимости неверно настроенного кинжала, как объяснено выше
  2. Отсутствует реализация реализации Rxjava и модификации
  3. Отсутствует URL обеспечивает et c

Чтобы исправить вышеперечисленное, выполните следующие шаги:

  1. График зависимости неверно настроенного кинжала, как описано выше

a) MainActivity требует RestApiHelper, который предоставляется UrlComponent, а не AppComponent, поэтому сначала используйте UrlComponent в качестве зависимостей вместо AppComponent

@PerActivity
@Component(modules = ActivityModule.class, dependencies = {UrlComponent.class})
public interface ActivityComponent {

    void inject(MainActivity mainActivity);

}

b) Теперь выставьте зависимость в UrlComponent

@PerUrl
@Subcomponent(modules = UrlModule.class)
public interface UrlComponent {
    RestApiHelper getRetrofit();
}

Реализация UrlModule.class с исправленными проблемами (упомянутыми выше)

import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import java.util.concurrent.TimeUnit;    
import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

@Module
public class UrlModule {
    private String url;

    public UrlModule(String url) {
        this.url = url;
    }

    @Provides
    @PerUrl
    OkHttpClient provideOkhttpClient() {
        return new OkHttpClient.Builder()
                .connectTimeout(20, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();
    }

    @Provides
    String provideUrl() {
        return url;
    }

    @Provides
    @PerUrl
    Retrofit provideRetrofit(String baseURL, OkHttpClient client) {

        return new Retrofit.Builder()
                .baseUrl(baseURL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();
    }


    @Provides
    RestApi provideApiService(Retrofit retrofit) {
        return retrofit.create(RestApi.class);
    }
}

c) URL сборки appComponent и urlComponent in Класс приложения для последующего использования как

public class ExampleApplication extends Application {

    // note, I remove the inject, you were doing it for testing etc
    private ApplicationComponent appComponent;

    private UrlComponent urlComponent;

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

        appComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this)).build();

        urlComponent = appComponent.plus(new UrlModule("https://jsonplaceholder.typicode.com/"));


    }

    public ApplicationComponent getAppComponent() {
        return appComponent;
    }

    public UrlComponent getUrlComponent() {
        return urlComponent;
    }


}

Теперь создайте activityComponent в BaseActivity как

activityComponent= DaggerActivityComponent.builder()
                .activityModule(new ActivityModule(this))
                .urlComponent(((ExampleApplication)getApplication()).getUrlComponent())
                .build();

и используйте его в своем * 1 074 * as

public class MainActivity extends BaseActivity {


    @Inject
    RestApiHelper restApiHelper;
    Disposable disposable;
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        ActivityComponent component = getActivityComponent();
        component.inject(this);

        disposable = restApiHelper.getquestionlist(1)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) throws Exception {
                        Log.d(TAG, "accept: "+ o.toString());    
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                    }
                });
    }

    @Override
    protected void onDestroy() {
        disposable.dispose(); // best practice
        super.onDestroy();
    }
}

Вот и все.

Примечание : убедитесь, что ваши значения baseUrl и retrofit правильно настроены и имеют inte rnet разрешение приложения et c. Вы можете оптимизировать свой код дальше с помощью lambdas et c, так как я сохранил большую часть кода для понимания.

0 голосов
/ 07 февраля 2020

Прежде всего, ваш метод, который предоставляет RestApi, неверен. Я должен быть как

    @Provides
    public RestApi provideApiService(Retrofit retrofit) {
        return retrofit.create(RestApi.class);

    }
...