Android MVP 从 Presenter 打开 Activity,反模式?
Android MVP open Activity from Presenter, anti-pattern?
如果我从 Presenter 层打开一个 Activity
会不会是反模式?
如果是这样,我应该从视图层管理应用程序的导航吗?
在我看来,如果您从视图层打开一个 activity 会更好。我希望 Presenter 尽可能少地了解 Activity。
如果有什么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();
}
}
是的,这是一种反 mvp 模式。基于 MVP 中的 passive view,你失去了可测试性,因为你不必在你的演示者中处理 android 框架。
所以最好从视图层管理应用程序的导航。
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();
}
}
这种方式的另一个优点是可以很容易地用片段或视图替换 activity。
编辑 1:
说这种方式会打破关注分离和单一职责,但你不能在每个地方都有单一职责。有时您需要违反它。这是来自 Google 的 MVP 示例:
TaskDetailPresenter
calls ShowEditTask
负责在TaskDetailFragment
.
里面开一个新的Activity
但是你也可以使用 CommandPattern 这是更好的方法
interface NavigationCommand {
void navigate();
}
因此,Presenter 会在需要时使用它。
正如我在对 的评论中所写,我认为从视图层管理导航明显违反了关注点分离规则:视图应仅包含更新当前 [=22= 的方法] 屏幕。
问题源于 android 平台设计,因为 Activity
和 Fragment
类 包含在 UI 屏幕上操作和发送意图的方法开始其他活动的对象,例如 startActivity
.
解决这个问题的一个干净的方法是创建一些 Navigator
接口,其中包含与导航相关的方法,让活动实现它并将它也注入到演示者中。这样至少从演示者的角度来看,导航和 UI 操作将分开。然而,从活动的角度来看,这可能看起来很奇怪:现在它们通常会实现两个接口(Navigator 和 View)并将它们的引用传递给演示者 2 次。如果因为这个原因你决定从视图层管理导航,那么至少要将导航方法与操作方法分开 UI:永远不要在同一方法中执行导航和 UI 操作。
我已经做了这个解决方案(在 Kotlin 中):
我创建了一个名为 ViewNavigator 的界面
interface ViewNavigator {
fun navigateTo(target: Class<*>)
}
然后我让视图接口实现它
interface View : ViewNavigator {
//...
}
然后实际视图(activity)可以覆盖navigateTo
函数
override fun navigateTo(target: Class<*>) {
startActivity(Intent(this, target))
}
因此,无论何时我想导航到任何 activity,我都可以简单地在演示者 class 中编写它。例如:
override fun onAnimationFinished() {
view.navigateTo(HomeActivity::class.java)
}
如果我从 Presenter 层打开一个 Activity
会不会是反模式?
如果是这样,我应该从视图层管理应用程序的导航吗?
在我看来,如果您从视图层打开一个 activity 会更好。我希望 Presenter 尽可能少地了解 Activity。
如果有什么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();
}
}
是的,这是一种反 mvp 模式。基于 MVP 中的 passive view,你失去了可测试性,因为你不必在你的演示者中处理 android 框架。
所以最好从视图层管理应用程序的导航。
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();
}
}
这种方式的另一个优点是可以很容易地用片段或视图替换 activity。
编辑 1:
TaskDetailPresenter
calls ShowEditTask
负责在TaskDetailFragment
.
Activity
但是你也可以使用 CommandPattern 这是更好的方法
interface NavigationCommand {
void navigate();
}
因此,Presenter 会在需要时使用它。
正如我在对
问题源于 android 平台设计,因为 Activity
和 Fragment
类 包含在 UI 屏幕上操作和发送意图的方法开始其他活动的对象,例如 startActivity
.
解决这个问题的一个干净的方法是创建一些 Navigator
接口,其中包含与导航相关的方法,让活动实现它并将它也注入到演示者中。这样至少从演示者的角度来看,导航和 UI 操作将分开。然而,从活动的角度来看,这可能看起来很奇怪:现在它们通常会实现两个接口(Navigator 和 View)并将它们的引用传递给演示者 2 次。如果因为这个原因你决定从视图层管理导航,那么至少要将导航方法与操作方法分开 UI:永远不要在同一方法中执行导航和 UI 操作。
我已经做了这个解决方案(在 Kotlin 中):
我创建了一个名为 ViewNavigator 的界面
interface ViewNavigator {
fun navigateTo(target: Class<*>)
}
然后我让视图接口实现它
interface View : ViewNavigator {
//...
}
然后实际视图(activity)可以覆盖navigateTo
函数
override fun navigateTo(target: Class<*>) {
startActivity(Intent(this, target))
}
因此,无论何时我想导航到任何 activity,我都可以简单地在演示者 class 中编写它。例如:
override fun onAnimationFinished() {
view.navigateTo(HomeActivity::class.java)
}