[英]Dagger 2.11: Local Singleton when using @ContributesAndroidInjector
I have a working Dagger setup using the @ContributesAndroidInjector annotation ( https://google.github.io/dagger/android.html ). 我使用@ContributesAndroidInjector注释( https://google.github.io/dagger/android.html )进行了有效的Dagger设置。
Component Application
/ \
Subcomponent DrawerActivity Subcomponent SubActivity
|
Subcomponent DrawerFragment
In SubActivity and DrawerActivity I am using the same repository instance which is marked as @Singleton. 在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);
}
}
I have now the need to add a user management. 我现在需要添加用户管理。 This requires a LoginActivity.
这需要LoginActivity。 I don't want the repository to be avaiblable in LoginActivity.
我不希望存储库在LoginActivity中可用。 So I'd like to create a local singleton scope "UserScope" for DrawerActivity/Subactivity/DrawerFragement
所以我想为DrawerActivity / Subactivity / DrawerFragement创建一个本地单例范围“UserScope”
Component Application
/ \
@UserScope @LoginScope
Subcomponent DrawerActivity SubComponent LoginActivity
| \
Subcomponent DrawerFragment Subcomponent SubActivity
How can I achieve this still using the new @ContributesAndroidInjector annotation? 如何使用新的@ContributesAndroidInjector注释实现此目的?
I want it to work like in this blogpost: http://frogermcs.github.io/building-userscope-with-dagger2/ 我希望它像在这篇博文中一样工作: http : //frogermcs.github.io/building-userscope-with-dagger2/
I solved my problem by doing it like in this repo: 我在这个回购中解决了我的问题:
https://github.com/ragdroid/Dahaka https://github.com/ragdroid/Dahaka
Many thanks to its contributor! 非常感谢它的贡献者!
Update 1 : Code example added. 更新1 :添加了代码示例。
This graph gives a rough idea of the code example. 该图提供了代码示例的粗略概念。
Component Application
/ \
@UserScope @LoginScope
Subcomponent UserComponent SubComponent LoginActivity
| \
Subcomponent DrawerActivity Subcomponent SubActivity
|
SubComponent DrawerFragment
Code Example (If somethings missing please let me know in the comments): 代码示例 (如果缺少某些内容请在评论中告诉我):
1. Dagger Setup 1.匕首设置
AppComponent is the root of Dagger graph: 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 which binds its SubComponents: 绑定其子组件的模块:
@Module(subcomponents = UserComponent.class)
public abstract class AppBindingModule {
@ContributesAndroidInjector(modules = LoginModule.class)
@LoginScope
abstract LoginActivity loginActivity();
}
UserComponent holds instances of classes that are used only when user is logged in. All classes provided in UserModule.class are available as "LocalSingletons" in further subcomponents like activities and fragment components. 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 defines which activity-subcomponents belong to UserComponent. UserBindingModule定义哪些活动子组件属于UserComponent。
@Module
public abstract class UserBindingModule {
@ContributesAndroidInjector(modules = {DrawerBindingModule.class, AndroidSupportInjectionModule.class})
abstract DrawerActivity bindDrawerActivity();
@ContributesAndroidInjector
abstract SubActivity bindSubActivity();
}
DrawerBindingModule defines which fragment-subcomponents belong to DrawerActivityComponent. DrawerBindingModule定义哪些片段子组件属于DrawerActivityComponent。
@Module
public abstract class DrawerBindingModule {
@DrawerFragmentScope
@ContributesAndroidInjector(modules = DrawerFragmentModule.class)
abstract DrawerFragment provideDrawerFragment();
}
The UserManager handles user login/logout and all further activity injections. 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 classes 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;
}
}
Application
(there are default scope with annotation @Singleton
already available), Activity
, BroadcastReceiver
, Fragment
, Service
, ContentProvider
(this list I took from DaggerApplication
). Application
(默认范围内注释@Singleton
已经可用), Activity
, BroadcastReceiver
, Fragment
, Service
, ContentProvider
(我从DaggerApplication
这个列表)。 So depends on what object it will be based you'll get reusable dependency inside lifecycle of this object (it will be local singleton for it, eg for activity/fragment) @ContributesAndroidInjector
for generating @Subcomponent
. @ContributesAndroidInjector
来生成@Subcomponent
。 This subcomponent should be scoped so that's why we put @FragmentScope
(created annotation by ourselves) on it. @FragmentScope
(我们自己创建了注释)放在它上面。 Two child fragments will belong to this subcomponent and that is the reason why we creating standalone module for child fragments and add it into generated Subcomponent by adding argument modules
to @ContributesAndroidInjector
of parent fragment subcomponent. 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
}
I omit some details like describing AppComponent and adding AppBindingModule into it and showing how to inject with AndroidSupportInjection.inject(this) cause it is out of the topic. 我省略了一些细节,比如描述AppComponent并将AppBindingModule添加到其中,并展示如何使用AndroidSupportInjection.inject(this)注入它,因为它不在主题中。 But if clarification is necessary feel free to ask questions in comment.
但如果需要澄清,请随意在评论中提问。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.