簡體   English   中英

Dagger 2.11:使用@ContributesAndroidInjector時的Local Singleton

[英]Dagger 2.11: Local Singleton when using @ContributesAndroidInjector

我使用@ContributesAndroidInjector注釋( https://google.github.io/dagger/android.html )進行了有效的Dagger設置。

        Component Application
       /                     \
Subcomponent DrawerActivity   Subcomponent SubActivity
      |
Subcomponent DrawerFragment

在SubActivity和DrawerActivity中,我使用標記為@Singleton的相同存儲庫實例。

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        ActivityBuilderModule.class
})
public interface AppComponent {
    @Component.Builder
    interface Builder{
        @BindsInstance Builder application(Application application);

        AppComponent build();
    }
    void inject(App app);
}

@Module
public abstract class ActivityBuilderModule {
    @PerActivity
    @ContributesAndroidInjector(modules = {DrawerActivityModule.class, 
    FragmentBuilderModule.class})
    abstract DrawerActivity bindDrawerActivity();

    @PerActivity
    @ContributesAndroidInjector(modules = {DrawerActivityModule.class})
    abstract SubActivity bindSubActivity();
}

@Module
public abstract class FragmentBuilderModule {
    @PerFragment
    @ContributesAndroidInjector(modules = DrawerFragmentModule.class)
    abstract DrawerFragment provideDrawerFragment();
}


@Singleton
public class Repository{
    private SomeClass mSomeClass;

    @Inject
    public VehicleRepositoryImpl(SomeClass someClass) {
        mSomeClass = someClass;
    }
}


public class App extends Application implements HasActivityInjector{
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.DEBUG) {
            Timber.plant(new Timber.DebugTree());
        }
        AppComponent component = DaggerAppComponent.builder().application(this)
                .build();
        component.inject(this);
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}    

public class DrawerActivity extends AppCompatActivity implements HasSupportFragmentInjector{
    @Inject
    DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;

    @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return fragmentDispatchingAndroidInjector;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

public class DrawerFragment extends Fragment {
    @Inject
    ViewModelFactory mViewModelFactory; //repository gets injected into factory

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        AndroidSupportInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

public class SubActivity extends AppCompatActivity{
    @Inject
    Repository mRepository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

我現在需要添加用戶管理。 這需要LoginActivity。 我不希望存儲庫在LoginActivity中可用。 所以我想為DrawerActivity / Subactivity / DrawerFragement創建一個本地單例范圍“UserScope”

              Component Application
           /                          \
   @UserScope                       @LoginScope 
   Subcomponent DrawerActivity      SubComponent LoginActivity
      |                        \
Subcomponent DrawerFragment   Subcomponent SubActivity

如何使用新的@ContributesAndroidInjector注釋實現此目的?

我希望它像在這篇博文中一樣工作: http//frogermcs.github.io/building-userscope-with-dagger2/

我在這個回購中解決了我的問題:

https://github.com/ragdroid/Dahaka

非常感謝它的貢獻者!

更新1 :添加了代碼示例。

該圖提供了代碼示例的粗略概念。

                 Component Application
           /                               \
   @UserScope                          @LoginScope 
   Subcomponent UserComponent          SubComponent LoginActivity
      |                      \
Subcomponent DrawerActivity   Subcomponent SubActivity
      |
SubComponent DrawerFragment

代碼示例 (如果缺少某些內容請在評論中告訴我):

1.匕首設置

AppComponent是Dagger圖的根:

@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        AppModule.class,
        AppBindingModule.class 
})
public interface AppComponent extends AndroidInjector<DaggerApplication> {
    @Component.Builder
    interface Builder{
        @BindsInstance Builder application(Application application);

        AppComponent build();
    }

    void inject(MyApp app);

    UserComponent.Builder userBuilder();

    UserManager getUserManager();
}

綁定其子組件的模塊:

@Module(subcomponents = UserComponent.class)
public abstract class AppBindingModule {

    @ContributesAndroidInjector(modules = LoginModule.class)
    @LoginScope
    abstract LoginActivity loginActivity();

}    

UserComponent保存僅在用戶登錄時使用的類的實例.UserModule.class中提供的所有類在其他子組件(如活動和片段組件)中可用作“LocalSingletons”

@UserScope
@Subcomponent(modules = {
        UserBindingModule.class,
        UserModule.class,
        AndroidSupportInjectionModule.class
})
public interface UserComponent extends AndroidInjector<DaggerApplication> {
    void inject(UserManager userManager);

    @Subcomponent.Builder
    interface Builder{
        UserComponent build();
    }
}

UserBindingModule定義哪些活動子組件屬於UserComponent。

@Module
public abstract class UserBindingModule {
    @ContributesAndroidInjector(modules = {DrawerBindingModule.class, AndroidSupportInjectionModule.class})
    abstract DrawerActivity bindDrawerActivity();

    @ContributesAndroidInjector
    abstract SubActivity bindSubActivity();
}

DrawerBindingModule定義哪些片段子組件屬於DrawerActivityComponent。

@Module
public abstract class DrawerBindingModule {
    @DrawerFragmentScope
    @ContributesAndroidInjector(modules = DrawerFragmentModule.class)
    abstract DrawerFragment provideDrawerFragment();
}

UserManager處理用戶登錄/注銷以及所有進一步的活動注入。

@Singleton
public class UserManager implements HasActivityInjector {
    private final UserComponent.Builder userComponentBuilder;
    @Inject
    DispatchingAndroidInjector<Activity> activityInjector;

    private UserComponent userComponent;

    @Inject
    public UserManager(UserComponent.Builder builder) {
        this.userComponentBuilder = builder;
    }

    public void logIn(){
        createUserSession();
    }

    private void createUserSession() {
        userComponent = userComponentBuilder.build();
        userComponent.inject(this);
    }

    public boolean isLoggedIn() {
        return userComponent != null;
    }

    public void logOut() {
        userComponent = null;
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return activityInjector;
    }
}

2. App + Activity + Fragment類

public class MyApp extends Application implements HasActivityInjector{
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Inject
    UserManager mUserManager;

    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.DEBUG) {
            Timber.plant(new Timber.DebugTree());
        }
        AppComponent component = DaggerAppComponent.builder().application(this)
                .build();
        component.inject(this);
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return mUserManager.activityInjector();
    }
}


public class LoginActivity extends AppCompatActivity {
    Intent mOpenDrawerActivity;
    private ActivityLoginBinding binding;

    @Inject
    UserManager mUserManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        ...
    }

    void openDrawerActivity(){
        mUserManager.logIn();
        mOpenDrawerActivity = new Intent(this, DrawerActivity.class);
        startActivity(mOpenDrawerActivity);
        finish();
    }
}


public class DrawerActivity extends BaseUserActivity implements HasSupportFragmentInjector{
    @Override
    protected void onCreate(Bundle savedInstanceState) {         
        super.onCreate(savedInstanceState);
        ...
    }        

    private void onLogout(){
        logoutUser();
    }  
}


public abstract class BaseUserActivity extends BaseActivity {
    @Inject
    UserManager userManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (!userManager.isLoggedIn()) {
            finishView();
        }
    }

    @Override
    protected void androidInject() {
        AndroidInjection.inject(this);
    }

    protected void logoutUser() {
        userManager.logOut();
        finishView();
    }    
}


public abstract class BaseActivity extends AppCompatActivity implements HasSupportFragmentInjector {
    @Inject
    DispatchingAndroidInjector<Fragment> injector;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        androidInject();
        super.onCreate(savedInstanceState);
    }

    protected void androidInject() {
        AndroidInjection.inject(this);
    }

    public void finishView() {
        startActivity(new Intent(this, LoginActivity.class));
        finish();
    }

    @Override
    public AndroidInjector<Fragment> supportFragmentInjector() {
        return injector;
    }
}
  1. 什么是范圍及其基礎? 范圍基於一些具有生命周期的android對象。 例如Application (默認范圍內注釋@Singleton已經可用), ActivityBroadcastReceiverFragmentServiceContentProvider (我從DaggerApplication這個列表)。 因此,取決於它將基於什么對象,您將在此對象的生命周期內獲得可重用的依賴項(它將是本地單例,例如對於activity / fragment)
  2. 如何使我的交互器/存儲庫成為本地單例? 首先,您應該選擇具有生命周期的對象,該對象將作為我們的范圍的基礎。 例如,讓我們選擇里面有兩個子片段的片段。 我想在這兩個子片段中使用相同的CommonInteractor實例。 我們應該為父片段創建獨立的子組件。 我們可以使用@ContributesAndroidInjector來生成@Subcomponent 這個子組件應該是作用域的,這就是為什么我們把@FragmentScope (我們自己創建了注釋)放在它上面。 兩個子片段將屬於此子組件,這就是我們為子片段創建獨立模塊並將其添加到生成的子組件中的原因,方法是將參數modules添加到父片段子組件的@ContributesAndroidInjector中。

@Module(includes = [AndroidInjectionModule::class])
abstract class AppBindingModule {
    //there are a lot of other android stuff binding here
    //activities, fragments, etc.

@FragmentScope @ContributesAndroidInjector(modules = [ParentFragmentModule::class]) abstract fun bindParentFragment(): ParentFragment } @Module abstract class ParentFragmentModule { //we should not annotate this by any scope annotation @ContributesAndroidInjector abstract fun bindFirstChildFragment(): FirstChildFragment @ContributesAndroidInjector abstract fun bindSecondChildFragment(): SecondChildFragment } @FragmentScope class CommonInteractor @Inject constructor() { //we can inject this interactor into presenters of those two child fragments //it will be the same instance for both presenters } class FirstChildPresenter @Inject constructor( private val commonInteractor: CommonInteractor ) : Presenter<FirstView>() class SecondChildPresenter @Inject constructor( private val commonInteractor: CommonInteractor ) : Presenter<SecondView>() class FirstChildFragment: Fragment(), FirstView { @Inject lateinit var firstChildPresenter: FirstChildPresenter } class SecondChildFragment: Fragment(), SecondView { @Inject lateinit var secondChildPresenter: SecondChildPresenter }

我省略了一些細節,比如描述AppComponent並將AppBindingModule添加到其中,並展示如何使用AndroidSupportInjection.inject(this)注入它,因為它不在主題中。 但如果需要澄清,請隨意在評論中提問。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM