正在刷新来自 Android 应用程序 class 的 Dagger 2 实例

Refreshing Dagger 2 instance from Android Application class

我的模块 class 中有一组 @Singleton@Provides 方法,用于在整个应用程序中创建 Singleton 实例。一切正常,除了少数瓶颈情况,如下所示:

第 1 步。我正在从 OKHttpClient 创建一个 Retrofit 实例,其中包含 Auth 令牌,以便每次都进行经过身份验证的 api 调用(Auth 令牌检索和插入是通过 SharedPreferences).但是问题开始于我通过清除数据库和共享首选项值注销应用程序后重新启动 activity。

第 2 步。注销后,我正在发出另一个请求以获取身份验证令牌并再次插入 SharedPreferences 以备将来使用。

第 3 步:现在,如果我继续 api 调用的其余部分,Dagger @Singleton@Provides 方法的先前实例将保持不变,除非并且直到我重新启动应用程序通过从最近的任务中清除它。 (新的授权令牌未更新)

需要修复:

  1. 如何强制触发Dagger provider 方法再次触发或撤销?

  2. 是否有任何方法可以刷新应用程序 class 数据,就像应用程序重新启动时一样。?

请找到我在项目中使用的 Dagger 2 架构:

NetworkModule.java(匕首模块class)

@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(匕首组件class)

@Singleton
@Component(modules =  {NetworkModule.class})
public interface AppComponent {


    //ACtivity
    void inject(AuthenticationActivity authenticationActivity);


    void inject(MainActivity mainActivity);


    //Fragments

    void inject(ProjectsListFragment projectsListFragment);



}

Application.java(Class用于创建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 天里我完全受困于此。我很无能和困惑,因为我的完整架构是建立在这个之上的。请原谅我的错别字和更正。如果需要任何澄清,请联系我。提前致谢。

How to trigger the Dagger provider methods forcibly to trigger or revoke it again?

Is there any method to refresh the application class data as similar behaviour like when the app relaunches?

不,没有这样的触发器。 Component 负责为您提供依赖项。如果你完成了一个 Component 并且你想使它无效(即你的依赖项被再次创建)你必须从它中删除(无效)并创建一个新的 Component。现在将再次创建所有依赖项。

您的问题是@Singleton@Singleton 告诉 Dagger 你希望 Dagger 缓存和管理实例状态,当你这样做时你不会获得很多控制来刷新实例。但是,欢迎您从 @Provides 方法中删除 @Singleton 并自行管理该实例。如果没有作用域,Dagger 将为每个注入请求调用您的 @Provides 方法,这将使您 return 任何您希望的实例并在适当的时候使它无效。

参见 this answer from yesterday,顺便说一下,它也是关于 Retrofit-serving 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 可能是有意义的。

根据 azizbekian 解决方案,我稍微修改了代码,效果非常好。非常感谢!

如果用户单击注销按钮,我将清除 SharedPreference 并通过应用程序中自定义创建的方法将 dagger 组件指定为 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();


    }

Application.java

    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();
    }
            }