我有一个LoginActivity,用户通过Auth0登录并返回一个身份验证令牌。此标记将传递给MainActivity:
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.putExtra(KEY_ACCESS_TOKEN, credentials.getAccessToken());
intent.putExtra(KEY_ID_TOKEN, credentials.getIdToken());
startActivity(intent);
我能够通过following this guide使用LoginActivity来完成依赖注入工作。
现在我正在尝试将依赖项注入MainActivity。我的MainActivity有一个MainActivityViewModel
来处理UI和数据层之间的所有交互。我想将我的API注入我的ViewModel:
PetshackApi apiService;
@Inject
public PetMapViewModel(PetshackApi apiService) {
this.apiService = apiService;
}
我定义了ViewModelModule
,ViewModelKey
和MainActivityViewModelFactory
(从GithubViewModelFactory重命名)。我在我的MainActivity顶部注入了viewModelFactory:
@Inject
ViewModelProvider.Factory viewModelFactory;
然后使用工厂获取我的viewModel:
viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainActivityViewModel.class);
我使用this answer进行了设置。
问题是我的Retrofit / PetshackApi依赖项需要LoginActivity中的accessToken
。所以我在MainActivity中定义了另一种方法来允许检索它:
public String getAccessToken() {
return getIntent().getStringExtra(LoginActivity.KEY_ACCESS_TOKEN);
}
我在设置模块/组件时遇到问题/ ???我想我需要以某种方式将MainActivity注入到我的模块中,所以我尝试了Injecting Activity objects。
MainActivityComponent.java
@Component(modules={AndroidSupportInjectionModule.class, AppModule.class, MainActivityModule.class, ViewModelModule.class})
public interface MainActivityComponent extends AndroidInjector<PetApplication> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<PetApplication>{
@BindsInstance
abstract Builder application(Application application);
}
void inject(MainActivity mainActivity);
}
MainActivityModule.java
@Module(subcomponents = MainActivitySubcomponent.class)
abstract class MainActivityModule {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindMainActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
}
MainActivitySubcomponent.java
@Subcomponent(modules = MainActivityChildModule.class)
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MainActivity> {}
}
MainActivityChildModule.java
@Module
abstract class MainActivityChildModule {
@Provides
@Singleton
Retrofit providesRetrofit(Application application, MainActivity mainActivity) {
final String accessToken = mainActivity.getAccessToken();
Interceptor interceptor = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("authorization", "Bearer " + accessToken).build();
return chain.proceed(newRequest);
}
};
// Add the interceptor to OkHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(interceptor);
OkHttpClient client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(application.getString(R.string.endpoint_url))
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
@Provides
@Singleton // needs to be consistent with the component scope
PetshackApi providesPetshackApiInterface(Retrofit retrofit) {
return retrofit.create(PetshackApi.class);
}
}
我是否在正确的轨道上?有关如何执行此操作的任何提示或示例?
答案 0 :(得分:1)
我建议您将网络代码移到Activity模块之外,并创建一个可在整个应用程序中共享的应用程序模块。
重要的是,如果您有一个为每个请求提供令牌的TokenStore,您需要在发送请求时更新该值。
@Module
abstract class NetworkModule {
@Provides
@Singleton
static TokenStore provideTokenStore(TokenStoreImpl tokenStore) {
return tokenStore;
}
@Provides
@Singleton
static OkHttpClient provideOkHttpClient(AuthInterceptor authInterceptor) {
// Add the interceptor to OkHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(authInterceptor);
return builder.build();
}
@Provides
@Singleton
static Retrofit providesRetrofit(Application application, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(application.getString(R.string.endpoint_url))
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
return retrofit;
}
@Provides
@Singleton // needs to be consistent with the component scope
static PetshackApi providesPetshackApiInterface(Retrofit retrofit) {
return retrofit.create(PetshackApi.class);
}
}
interface TokenStore {
String getToken();
void setToken(String token);
}
@Singleton
class TokenStoreImpl implements TokenStore {
String token;
@Inject
public TokenStoreImpl() { }
@Override
public String getToken() {
return token;
}
@Override
public void setToken(String token) {
this.token = token;
}
}
@Singleton
class AuthInterceptor implements Interceptor {
private final TokenStore tokenStore;
@Inject
public AuthInterceptor(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request()
.newBuilder().addHeader("authorization", "Bearer " + tokenStore.getToken()).build();
return chain.proceed(newRequest);
}
}