我正在尝试按照此模板进行 MVP/Dagger2/RxJava 项目。
我无法将 Activity 上下文注入到我的演示者中,因为我知道子组件可以开放访问所有父提供的逻辑,所以其他所有注入都会通过。
应用程序组件构建在 Application 类中,然后在基础 Presenter 活动中访问,然后注入 Presenter 和其余部分的相关依赖项。配置持久化组件主要用于保存演示者状态。
如果我只是手动将上下文从活动传递给演示者,则违背了 DI 的目的。
我试图为所有组件和模块添加范围,以确保可以从图中正确访问依赖项,但这没有奏效。
我正在尝试使用上下文的构造函数注入,我实际上在演示者与之通信的活动中接收到上下文,但演示者没有,会引发错误。所以我想知道为什么活动可以访问活动上下文但演示者没有。
任何指导将不胜感激。
错误
Error:(13, 8) error: [<packageName>.injection.component.ActivityComponent.inject(<packageName>.login.LoginActivity)] android.app.Activity cannot be provided without an @Inject constructor or from an @Provides-annotated method.
android.app.Activity is injected at
<packageName>.login.presenter.LoginActivityPresenter.<init>(activity, …)
<packageName>.login.presenter.LoginActivityPresenter is injected at
<packageName>.login.LoginActivity.presenter
<packageName>.login.LoginActivity is injected at
<packageName>.injection.component.ActivityComponent.inject(loginActivity)
A binding with matching key exists in component: <packageName>.injection.component.ActivityComponent
我的组件/模块如下所示:
应用程序组件
@Singleton
@Component(modules = {ApplicationModule.class, BusModule.class, PrefsModule.class, NetModule.class})
public interface ApplicationComponent {
@ApplicationContext Context context();
Application application();
EventBus bus();
SharedPreferences prefs();
Gson gson();
}
应用模块
@Module
public class ApplicationModule {
protected final Application app;
public ApplicationModule(Application app) {
this.app = app;
}
@Provides
Application providesApplication() {
return app;
}
@Provides
@ApplicationContext
Context providesContext(){
return app;
}
}
配置持久化组件
@ConfigPersistent
@Component(dependencies = ApplicationComponent.class)
public interface ConfigPersistentComponent {
ActivityComponent plus(ActivityModule activityModule);
}
活动组件
@PerActivity
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(LoginActivity loginActivity);
}
活动模块
@Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
@Provides
@PerActivity
Activity providesActivity() {
return activity;
}
}
应用类
public class App extends Application {
private ApplicationComponent applicationComponent;
@Override public void onCreate() {
super.onCreate();
Timber.plant(new Timber.DebugTree());
}
public static App get(Context context) {
return (App) context.getApplicationContext();
}
public ApplicationComponent getComponent() {
if (applicationComponent == null) {
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.busModule(new BusModule())
.netModule(new NetModule())
.prefsModule(new PrefsModule())
.build();
}
return applicationComponent;
}
}
主讲者
@ConfigPersistent
public class LoginActivityPresenter extends BasePresenter<LoginContract.View> {
Context context;
Gson gson;
@Inject
public LoginActivityPresenter(Activity activity, Gson gson) {
this.context = activity;
this.gson = gson;
}
@Override public void attachView(LoginContract.View view) {
super.attachView(view);
Timber.d("onAttach");
}
@Override public void detachView() {
super.detachView();
Timber.d("onDettach");
disposableSubscriber.dispose();
}
}
基本演示者活动
public abstract class BasePresenterActivity extends AppCompatActivity {
private static final String KEY_ACTIVITY_ID = "KEY_ACTIVITY_ID";
private static final AtomicLong NEXT_ID = new AtomicLong(0);
private static final Map<Long, ConfigPersistentComponent> sComponentsMap = new HashMap<>();
private ActivityComponent activityComponent;
private long activityId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the ActivityComponent and reuses cached ConfigPersistentComponent if this is
// being called after a configuration change.
activityId = savedInstanceState != null ? savedInstanceState.getLong(KEY_ACTIVITY_ID) : NEXT_ID.getAndIncrement();
ConfigPersistentComponent configPersistentComponent;
if (!sComponentsMap.containsKey(activityId)) {
Timber.i("Creating new ConfigPersistentComponent id=%d", activityId);
configPersistentComponent = DaggerConfigPersistentComponent.builder()
.applicationComponent(App.get(this).getComponent())
.build();
sComponentsMap.put(activityId, configPersistentComponent);
} else {
Timber.i("Reusing ConfigPersistentComponent id=%d", activityId);
configPersistentComponent = sComponentsMap.get(activityId);
}
activityComponent = configPersistentComponent.plus(new ActivityModule(this));
}
主要活动
public class LoginActivity extends BasePresenterActivity implements LoginContract.View {
@Inject
EventBus bus;
@Inject
SharedPreferences prefs;
@Inject
Activity activity;
@Inject
LoginActivityPresenter presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityComponent().inject(this);
setContentView(R.layout.activity_login);
presenter.attachView(this);
}
@Override protected void onDestroy() {
super.onDestroy();
presenter.detachView();
}
}
/********** 编辑 **********/
为了帮助为演示者保存状态并仍然允许传入活动上下文,我的解决方案发布在下面。欢迎任何反馈。
@ActivityContext
public class LoginActivityPresenter extends BasePresenter<LoginContract.View> {
Context context;
@Inject
LoginStateHolder loginStateHolder;
@Inject
public LoginActivityPresenter(Context context, Gson gson) {
this.context = activity;
this.gson = gson;
}
}
@ConfigPersistent
public class LoginStateHolder {
String title;
@Inject
public LoginStateHolder(Context context) {
title = "Save me";
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
/*********编辑 - 21_5_17 *********/
例外:
Error:(13, 8) error: [<packagename>.injection.component.ActivityComponent.inject(<packagename>.login.ui.activity.LoginActivity)] android.app.Activity cannot be provided without an @Provides-annotated method.
android.app.Activity is injected at
<packagename>.login.presenter.LoginActivityPresenter.<init>(activity, …)
<packagename>.login.presenter.LoginActivityPresenter is injected at
<packagename>.login.ui.activity.LoginActivity.presenter
<packagename>.login.ui.activity.LoginActivity is injected at
<packagename>.injection.component.ActivityComponent.inject(loginActivity)
登录活动
public class LoginActivity extends BasePresenterActivity implements LoginContract.View {
@Inject
EventBus bus;
@Inject
SharedPreferences prefs;
@Inject
LoginActivityPresenter presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityComponent().inject(this);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
presenter.attachView(this);
presenter.setupValidation(username, companyId, password);
}
登录活动演示者
@ActivityContext
public class LoginActivityPresenter extends BasePresenter<LoginContract.View> {
@Inject LoginPresenterStorage loginPresenterStorage;
Gson gson;
@Inject
public LoginActivityPresenter(Activity activity, Gson gson) {
this.context = activity;
this.gson = gson;
}
}
登录演示者存储
@ConfigPersistent
public class LoginPresenterStorage {
private String test = "";
@Inject
public LoginPresenterStorage(Activity activity) {
test = "I didn't die";
}
public String getTest() {
return test;
}
}
应用组件
@Singleton
@Component(modules = {ApplicationModule.class, BusModule.class, PrefsModule.class, NetModule.class})
public interface ApplicationComponent {
@ApplicationContext Context context();
Application application();
EventBus bus();
SharedPreferences prefs();
Gson gson();
}
活动组件
@ActivityContext
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(LoginActivity loginActivity);
}
配置持久组件
@ConfigPersistent
@Component(dependencies = ApplicationComponent.class)
public interface ConfigPersistentComponent {
ActivityComponent plus(ActivityModule activityModule);
}
活动模块
@Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
@Provides
@ActivityContext
Activity providesActivity() {
return activity;
}
}
编辑
我错误地使用了与活动模块相同的活动上下文。因此,我无法将活动注入演示者。将活动模块更改为原始@peractivity 范围并遵循以下答案将使活动上下文可注入。