如果我在Presenter层打开一个Activity
,这算是反模式吗?
如果是的话,我应该从View层管理应用程序的导航吗?
class MyPresenter {
MyPresenter.View view;
void backButtonClicked() {
view.navigateToHomeScreen();
}
public interface View {
void navigateToHomeScreen();
}
}
class MyActivity extends Activity implements MyPresenter.View {
@Override
void navigateToHomeScreen() {
startActivity(...)
}
@OnClick(R.id.my_button)
void onClick() {
presenter.backButtonClicked();
}
}
另外,这种方式的另一个优点是容易将活动替换为片段或视图。
编辑1:
Morgwai 表示这种方法会破坏关注点分离和单一责任,但你不能在所有地方都保持单一责任。有时需要违反它。下面是 Google 提供的 MVP 示例:
TaskDetailPresenter
调用 ShowEditTask
,后者负责在 TaskDetailFragment
中打开新的 Activity
。
但也可以使用命令模式, 这是一种更好的方法。
interface NavigationCommand {
void navigate();
}
因此,当Presenter需要时会使用它。
Activity
和Fragment
类既包含操作UI屏幕的方法,还包含发送意图对象以启动其他活动(如startActivity
)的方法。Navigator
接口,其中包含与导航相关的方法,并使活动实现它并将其注入到演示者中。这样,至少从演示者的角度来看,导航和UI操作将被分开。但是,从活动的角度来看可能会很奇怪:现在他们经常同时实现两个接口(导航和视图)并将其引用传递给演示者两次。如果因此你决定从你的视图层管理导航,那么至少要将用于导航的方法与用于操纵UI的方法分开:永远不要在同一个方法中执行导航和UI操作。在我看来,最好从视图层打开一个活动。我希望Presenter尽可能少地了解Activity。
如果有某些条件需要启动活动,您可以使用类似以下代码:
public class Presenter {
private ViewsPresentation mViewsPresentation;
public void someButtonClicked() {
if (/*some condition*/) {
mViewsPresentation.startFirstActivity();
} else {
mViewsPresentation.startSecondActivity();
}
}
public interface ViewsPresentation {
void startFirstActivity();
void startSecondActivity();
}
}
interface ViewNavigator {
fun navigateTo(target: Class<*>)
}
interface View : ViewNavigator {
//...
}
然后实际视图(即活动)可以重写 navigateTo
函数。
override fun navigateTo(target: Class<*>) {
startActivity(Intent(this, target))
}
因此,每当我想导航到任何活动时,我只需在Presenter类中编写即可。例如:
override fun onAnimationFinished() {
view.navigateTo(HomeActivity::class.java)
}