作者:2414220942_d5ab70 | 来源:互联网 | 2023-02-07 21:29
我在我的模块类中有一组@Singleton
和@Provides
方法,用于在整个应用程序中创建Singleton实例.一切都很好,除了几个瓶颈情况,如下所示:
步骤1.我正在OKHttpClient
使用Auth令牌创建一个Retrofit实例,以便每次都进行经过身份验证的api调用(通过处理Auth令牌检索和插入SharedPreferences
).但是,在我通过清除数据库和共享首选项值注销应用程序之后重新启动活动时,问题就开始了.
步骤2.注销后,我正在另一个请求获取auth令牌并SharedPreferences
再次插入以供将来使用.
第3步:现在,如果我继续进行其余的api调用,则前面的Dagger @Singleton
和@Provides
方法实例保持相同,除非直到我通过从最近的任务中清除它来重新启动应用程序.(新的身份验证令牌未更新)
需要修复:
如何触发Dagger提供程序方法强制再次触发或撤消它?
是否有任何方法可以像应用程序重新启动时那样刷新应用程序类数据.
请找到我项目中使用的Dagger 2架构:
NetworkModule.java(Dagger Module类)
@Module
public class NetworkModule {
private Context context;
public NetworkModule(Application app) {
this.cOntext= app;
}
@Provides
@Named("network.context")
Context providesContext() {
return context;
}
@Singleton
@Provides
OkHttpClient providesOkHttpClient(@Named("network.context")final Context context) {
final UserProfile userProfile = GsonUtils.createPojo(SharedPrefsUtils.getString(Constants.SHARED_PREFS.USERS_PROFILE, "",context), UserProfile.class);
Logger.i(userProfile != null && !TextUtils.isEmpty(userProfile.getAuth_token()) ? userProfile.getAuth_token() : "----OAuth token empty---");
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("Api-Version", "application/vnd.addo-v1+json")
.header("Access-Token", userProfile != null && !TextUtils.isEmpty(userProfile.getAuth_token()) ? userProfile.getAuth_token() : "")
.header("App-Version", Utils.getVersionName(context))
.header("Device-Platform","android")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
return httpClient.build();
}
@Provides
@Named(Constants.INJECTION.BASE_URL)
String providebaseURL() {
return Constants.URL.BASE_URL;
}
@Singleton
@Provides
Retrofit providesRetrofit(@Named("network.context")Context context, @Named(Constants.INJECTION.BASE_URL) String baseURL, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
return retrofit;
}
@Singleton
@Provides
NetworkApiService providesNetworkApiService(Retrofit retrofit){
return retrofit.create(NetworkApiService.class);
}
@Singleton
@Provides
ProjectPresenter providesProjectPresenter(NetworkApiService networkApiService){
return new ProjectPresenterImpl(networkApiService);
}
}
AppComponent.java(Dagger组件类)
@Singleton
@Component(modules = {NetworkModule.class})
public interface AppComponent {
//ACtivity
void inject(AuthenticationActivity authenticationActivity);
void inject(MainActivity mainActivity);
//Fragments
void inject(ProjectsListFragment projectsListFragment);
}
Application.java(用于创建Dagger组件的类)
public class Application extends Application {
private AppComponent appComponent ;
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
ButterKnife.setDebug(BuildConfig.DEBUG);
appCompOnent= DaggerAppComponent.builder().appModule(new AppModule(this)).networkModule(new NetworkModule(this)).build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
请帮助我提出解决Dagger 2奇怪行为的建议或提示.任何类型的解决方案都会对我有所帮助,因为我在过去的6天里完全坚持了这一点.我无能为力,因为我的完整架构是建立在此之上的.请原谅我的拼写错误和更正.如果对此有任何澄清,请告诉我.提前致谢.
1> Jeff Bowman ..:
你的问题是@Singleton
.@Singleton
告诉Dagger您希望Dagger缓存并管理实例状态,并且在执行此操作时,您无法获得大量控制来刷新实例.但是,欢迎您@Singleton
从@Provides
方法中删除并自行管理该实例.如果没有范围,Dagger将为@Provides
每个注入请求调用您的方法,这将允许您返回您希望的任何实例并在适当时使其无效.
从昨天看到这个答案,顺便提一下,它也是一个改造服务的NetworkModule,以及在AppComponent上刷新实例的范围问题.(你们两个不在同一个团队,是吗?)
/* Module fields */
OkHttpClient myClient;
String lastToken;
/** Not @Singleton */
@Provides
OkHttpClient providesOkHttpClient(
@Named("network.context") final Context context, TokenManager tokenManager) {
String currentToken = getToken(); // gets token from UserProfile
if (myInstance == null || !lastToken.equals(currentToken)) {
lastToken = currentToken;
myInstance = createInstance(currentToken); // As you have it above
}
return myInstance;
}
没有办法自动刷新共享首选项,但使用上面的按需创建结构,只要当前令牌发生更改,您就可以轻松地将其写入数据持有者.此时,在另一个答案中提取NetworkManager可能是有意义的.
2> azizbekian..:
如何强制触发Dagger提供程序方法以再次触发或吊销它?
是否有任何方法可以像重新启动应用程序一样刷新应用程序类数据?
不,没有这样的触发条件。Component
负责为您提供依赖关系。如果您已经完成了一个操作Component
并且想要使它无效(即再次创建依赖),则必须从中删除(清空)并创建一个新对象Component
。现在,将再次创建所有依赖项。
您能否解释更多,如何配置组件?
3> Chandru..:
根据azizbekian解决方案,我对代码进行了一些修改,它的工作原理很吸引人。非常感谢!
如果使用单击注销按钮,我将清除SharedPreference并通过应用程序中自定义创建的方法将匕首组件分配为null clearComponent()
,然后将用户导航到另一个“身份验证”屏幕。请找到下面的完整代码。希望对您有所帮助!
@OnClick(R.id.img_logout)
void logout() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
alertDialog
.setMessage("Do you really want to logout?")
.setCancelable(false)
.setPositiveButton("Logout", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox, int id) {
// ToDo get user input here
SharedPrefsUtils.remove(KEY_USERPROFILE, getActivity());
((Application) getActivity().getApplication()).clearComponent();
ActivityUtils.launchActivity(getActivity(), AuthenticationActivity.class, true);
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox, int id) {
dialogBox.cancel();
}
});
AlertDialog alertDialogAndroid = alertDialog.create();
alertDialogAndroid.show();
}
应用程序
public class Application extends Application {
private AppComponent appComponent ;
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
ButterKnife.setDebug(BuildConfig.DEBUG);
appCompOnent= createDaggerComponent();
}
public AppComponent getAppComponent() {
return appCompOnent== null ? createDaggerComponent() : appComponent;
}
public void clearComponent() {
appCompOnent= null;
}
private AppComponent createDaggerComponent() {
return DaggerAppComponent.builder().appModule(new AppModule(this)).networkModule(new NetworkModule(this)).build();
}
}