Refreshing Dagger 2 from Android Application Class

I have a set of methods @Singletonand @Providesin my module class to create an instance of Singleton in the application. Everything works fine except for a few bottleneck scenarios, for example:

STEP 1. I create an instance of Retrofit from OKHttpClientwith the Auth token in it to receive authenticated api calls each time (receiving and entering the Auth token is processed through SharedPreferences). But the problem starts when activity is restarted after I exit the application, clearing the databases and general settings values.

STEP 2. After logging out, make another request to extract auth tokens and add them SharedPreferencesagain for future use.

STEP 3: Now, if I keep the rest api calls, the previous instance method Dagger @Singletonand @Provideswill remain the same, if, and as long as I have not restarted the application, ridding it of a recent problem. (The new authentication token is not updated)

Corrections required:

  • How to force Dagger provider methods to force call or cancel it again?

  • Is there a way to update the application class data as a similar behavior, for example, when the application restarts.

Please find my Dagger 2 architecture used in my project:

NetworkModule.java (dagger module 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 (Dagger component 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 (the class used to create the Dagger component)

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

    }

2. , 6 . , . , . , - , . .

+4
3

Dagger , ?

, , ?

, . Component . Component (.. ), (null out) Component. .

+2

. !

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


    }

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

@Singleton. @Singleton , , , , , . @Singleton @Provides . , @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;
}

It is not possible to automatically update general settings, but with the specified create-on-demand structure, you can easily write it to the data holder whenever the current token changes. At this point, it might make sense to extract the NetworkManager, as in another answer.

+3
source

Source: https://habr.com/ru/post/1673699/


All Articles