我的应用程序中有两个不同的匕首组件:MainComponent
和UserComponent
。 UserComponent
是MainComponent
的子组件,@UserScope
仅在用户登录后才存在。
当我需要注入仅在用户登录或注销时才存在的类时,它可以正常工作。但是有两种情况根本无法奏效:
当用户登录时某些类可以存在,也可以不存在。例如,这可以是一个片段,其中显示商品列表和可选的“购买”按钮,这些按钮仅在用户登录后才可见。或者推送通知服务-推送通知可能会到达,无论用户是否登录,您都可以需要针对不同的用户以不同的方式处理它们。 在这种情况下,类在初始化期间必须注入不同的组件。
也有一些类的寿命超过@UserScope
。例如,带有侧面菜单的活动。侧边菜单在顶部显示用户头像和名称,但在底部也包含“退出”按钮。当用户按下退出键时,活动应更改菜单标题。 在这种情况下,必须在创建类后将类重新注入。
如何处理这种情况?
想到的唯一可能的解决方案是在用户注销后用空用户创建UserComponent
,然后从模块中所有@Provides
方法中返回空值,但这是很多工作。此外,我希望UserComponent
在用户注销时为空,而不是使用已失效的版本。
我真的很喜欢这样的东西:
if (Injector.userComponent() != null) {
Injector.userComponent().inject(this);
} else {
Injector.mainComponent().inject(this);
}
但是此代码给出错误:IUser cannot be provided without an @Provides-annotated method.
,因为MainComponent不提供IUser。但这确实不应该。
没有办法告诉匕首只留下无法找到空值的字段吗?
以下是我当前的实现方式:
@Singleton
@Component(modules = {
ApplicationModule.class,
AuthorizationModule.class
})
public interface MainComponent {
void inject(MyClass item);
...
UserComponent.Builder userComponentBuilder();
}
@Scope
public @interface UserScope {
}
@UserScope
@Subcomponent(modules = {
UserModule.class
})
public interface UserComponent {
void inject(MyClass item);
...
@Subcomponent.Builder
interface Builder {
Builder userModule(UserModule module);
UserComponent build();
}
}
@Module
public class UserModule {
private User mUser;
public UserModule(User user) {
mUser = user;
}
@Provides
@UserScope
IUser user() {
return mUser;
}
}
public class Injector {
private static MainComponent sMainComponent;
private static UserComponent sUserComponent;
public static void createMainComponent(MainApplication application) {
sMainComponent = DaggerMainComponent.builder()
.applicationModule(new ApplicationModule(application))
.build();
}
@NonNull
public static MainComponent mainComponent() {
return sMainComponent;
}
public static void createUserComponent(User user) {
if (user == null) {
throw new NullPointerException("Cannot create user component without a user");
}
sUserComponent = sMainComponent.userComponentBuilder()
.userModule(new UserModule(user))
.build();
}
public static void destroyUserComponent() {
sUserComponent = null;
}
@Nullable
public static UserComponent userComponent() {
return sUserComponent;
}
}
public class MyClass {
// Provided by MainComponent
@Inject
IAuthorizationManager mAuthorizationManager;
// Provided by UserComponent
@Inject
IUser mUser;
public MyClass() {
// Works, but not if userComponent is currently null (user is not logged in):
Injector.userComponent().inject(this);
// Doesn't work, but I'd prefer something like that instead of creating invalid UserComponent:
if (Injector.userComponent() != null) {
Injector.userComponent().inject(this);
} else {
Injector.mainComponent().inject(this);
}
}
}
答案 0 :(得分:0)
最后,我决定只让UserModule提供的依赖项为Nullable,同时使UserComponent为NonNull。
这意味着在使用UserModule的依赖项的任何地方,都必须将其声明为Nullable。这通常会引起误解,因为如果类是由UserModule创建的,并且仅在用户存在时才存在,则其内部的依赖项肯定是NonNull,但是您不能强制这样做。
如果有人感兴趣,请附加修改后的示例代码。
@Singleton
@Component(modules = {
ApplicationModule.class,
AuthorizationModule.class
})
public interface MainComponent {
void inject(MyClass item);
...
UserComponent.Builder userComponentBuilder();
}
@Scope
public @interface UserScope {
}
@UserScope
@Subcomponent(modules = {
UserModule.class
})
public interface UserComponent {
void inject(MyClass item);
...
@Subcomponent.Builder
interface Builder {
Builder userModule(UserModule module);
UserComponent build();
}
}
@Module
public class UserModule {
@Nullable
private User mUser;
public UserModule(@Nullable User user) {
mUser = user;
}
@Provides
@Nullable
@UserScope
IUser user() {
return mUser;
}
}
public class Injector {
private static MainComponent sMainComponent;
private static UserComponent sUserComponent;
public static void createMainComponent(MainApplication application) {
sMainComponent = DaggerMainComponent.builder()
.applicationModule(new ApplicationModule(application))
.build();
}
@NonNull
public static MainComponent mainComponent() {
return sMainComponent;
}
public static void createUserComponent(@Nullable User user) {
sUserComponent = sMainComponent.userComponentBuilder()
.userModule(new UserModule(user))
.build();
}
@NonNull
public static UserComponent userComponent() {
return sUserComponent;
}
}
public class MyClass {
@Inject
IAuthorizationManager mAuthorizationManager;
@Inject
@Nullable
IUser mUser;
public MyClass() {
Injector.userComponent().inject(this);
}
}