java - Dagger 2.11 : Local Singleton when using @ContributesAndroidInjector

标签 java android dagger-2

我有一个使用@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/

最佳答案

我像在这个 repo 中那样解决了我的问题:

https://github.com/ragdroid/Dahaka

非常感谢它的贡献者!

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

此图给出了代码示例的粗略概念。

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

代码示例(如果缺少某些内容,请在评论中告诉我):

<强>1。 Dagger 设置

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

绑定(bind)其子组件的模块:

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

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

}    

UserComponent 包含仅在用户登录时使用的类实例。UserModule.class 中提供的所有类在 Activity 和 fragment 组件等其他子组件中都可用作 “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 定义哪些 Activity 子组件属于 UserComponent。

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

    @ContributesAndroidInjector
    abstract SubActivity bindSubActivity();
}

DrawerBindingModule 定义哪些 fragment 子组件属于 DrawerActivityComponent。

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

UserManager 处理用户登录/注销和所有进一步的 Activity 注入(inject)。

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

关于java - Dagger 2.11 : Local Singleton when using @ContributesAndroidInjector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47271596/

相关文章:

java - 如何合并多个pdf

java - 如何修复imagebutton onclicklistener的空指针异常?

android - 字节码注入(inject)后的 java.lang.VerifyError

安卓错误 “unable to find explicit activity class”

android - 无法访问 ActivityCompatApi23 - Kotlin - AndroidX - Dagger 2.17

java - 在 Dagger 中实现单例构建器

java - rmi.transport.tcp.tcptransport Connectionhandler 占用大量 CPU

java - BigDecimal 与 BigInteger 和 BigDecimal 的性能比较

java - 使用自定义按钮关闭具有自定义界面的警报对话框

java - 使用组件依赖时的单例问题