Dagger2+Retrofit 更改 URL 与子组件:没有 @Provides- 或 @Produces-annotated 方法无法提供
Dagger2+Retrofit change URL with Subcomponent : cannot be provided without an @Provides- or @Produces-annotated method
我是 Dagger 的新手。我在运行时使用 更改 URL。
我还使用了三个模块和三个组件,如下所示:
注意:我有两个组件 (ApplicationComponent,ActivityComponent
) 和一个子组件 (UrlComponent
) 此外,我使用 @Singletone
、@PerUrl
和 @PerActivty
作为范围。
当我想 Inject
RestApi
进入每个 Activity 我遇到这个错误:
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();
}
ExampleApplication.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
中内置的所有 Provider 添加到 ApplicationModule
(UrlModule is Subcomepoent of the ApplicationComponent
)
@PerActivity
@Component(modules = ActivityModule.class,dependencies = ApplicationComponent.class)
public interface ActivityComponent {
并且由于 ApplicationComponent 是一个 Activity 组件依赖项,所有这些 Providers
是否也可以在 Activity 组件中使用?
2-作为一个基本问题,问题出在哪里?
首先你提供RestApi的方法是错误的。
我应该像
@Provides
public RestApi provideApiService(Retrofit retrofit) {
return retrofit.create(RestApi.class);
}
Shouldn't all the Providers built into the Urlmodule be added to
ApplicationModule(UrlModule is Subcomepoent of the
ApplicationComponent )
当您声明组件依赖项时,依赖组件只能使用在 dependencies
的组件 class 内声明的公开依赖项,在您的情况下,这些是 context
和application
在您的 ApplicationComponent
class 中,由 ApplicationModule
提供。
用于验证(测试):
1) 在您的应用程序模块中添加一个新的 provides
// inside ApplicationModule
@Provides
Student getNum() {
return new Student("aa");
}
2) 创建并使用 ActivityComponent
对象将 Student
注入任何 class。这将导致缺少供应。它可以通过在 ApplicationComponent
class 中公开 Student
来修复:
Student getStu();
2-And as a basic question, where is the problem?
具有以下实现:
- Dagger 错误配置的依赖关系图,如上所述
- 缺少
Rxjava
实施和改造实施
- 缺少 url 提供等
要解决上述问题,请按照以下步骤操作:
- Dagger misconfigured dependancy graph, as explained above
a) MainActivity
需要 UrlComponent
而不是 AppComponent
提供的 RestApiHelper
所以首先使用 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) 在应用程序 class 中构建 Url appComponent
和 urlComponent
供以后用作
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;
}
}
现在将 BaseActivity
中的 activityComponent
构建为
activityComponent= DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.urlComponent(((ExampleApplication)getApplication()).getUrlComponent())
.build();
并在您的 MainActivity
中使用它作为
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
对象设置正确并且具有互联网应用程序权限等。您可以进一步优化您的代码lambdas 等,因为我保留了大部分代码以供理解。
我是 Dagger 的新手。我在运行时使用
我还使用了三个模块和三个组件,如下所示:
注意:我有两个组件 (ApplicationComponent,ActivityComponent
) 和一个子组件 (UrlComponent
) 此外,我使用 @Singletone
、@PerUrl
和 @PerActivty
作为范围。
当我想 Inject
RestApi
进入每个 Activity 我遇到这个错误:
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();
}
ExampleApplication.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
中内置的所有 Provider 添加到 ApplicationModule
(UrlModule is Subcomepoent of the ApplicationComponent
)
@PerActivity
@Component(modules = ActivityModule.class,dependencies = ApplicationComponent.class)
public interface ActivityComponent {
并且由于 ApplicationComponent 是一个 Activity 组件依赖项,所有这些 Providers
是否也可以在 Activity 组件中使用?
2-作为一个基本问题,问题出在哪里?
首先你提供RestApi的方法是错误的。 我应该像
@Provides
public RestApi provideApiService(Retrofit retrofit) {
return retrofit.create(RestApi.class);
}
Shouldn't all the Providers built into the Urlmodule be added to ApplicationModule(UrlModule is Subcomepoent of the ApplicationComponent )
当您声明组件依赖项时,依赖组件只能使用在 dependencies
的组件 class 内声明的公开依赖项,在您的情况下,这些是 context
和application
在您的 ApplicationComponent
class 中,由 ApplicationModule
提供。
用于验证(测试):
1) 在您的应用程序模块中添加一个新的 provides
// inside ApplicationModule
@Provides
Student getNum() {
return new Student("aa");
}
2) 创建并使用 ActivityComponent
对象将 Student
注入任何 class。这将导致缺少供应。它可以通过在 ApplicationComponent
class 中公开 Student
来修复:
Student getStu();
2-And as a basic question, where is the problem?
具有以下实现:
- Dagger 错误配置的依赖关系图,如上所述
- 缺少
Rxjava
实施和改造实施 - 缺少 url 提供等
要解决上述问题,请按照以下步骤操作:
- Dagger misconfigured dependancy graph, as explained above
a) MainActivity
需要 UrlComponent
而不是 AppComponent
提供的 RestApiHelper
所以首先使用 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) 在应用程序 class 中构建 Url appComponent
和 urlComponent
供以后用作
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;
}
}
现在将 BaseActivity
中的 activityComponent
构建为
activityComponent= DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.urlComponent(((ExampleApplication)getApplication()).getUrlComponent())
.build();
并在您的 MainActivity
中使用它作为
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
对象设置正确并且具有互联网应用程序权限等。您可以进一步优化您的代码lambdas 等,因为我保留了大部分代码以供理解。