[英]Android MVP open Activity from Presenter, anti-pattern?
Would it be an anti-pattern if from a Presenter layer I open an Activity
?如果我从 Presenter 层打开一个
Activity
它会是一个反模式吗?
If so, should I manage the navigation of the app from the View Layer?如果是这样,我应该从视图层管理应用程序的导航吗?
Yes it's an anti-mvp-pattern. 是的,这是一个反mvp模式。 Based on passive view in MVP, you lost your testability, because you don't have to deal with the android framework in your presenter.
基于MVP中的被动视图 ,您失去了可测试性,因为您不必在演示者中处理Android框架。
So it's better to manage the navigation of the app from the View Layer. 因此,最好从视图层管理应用程序的导航。
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();
}
}
Also another advantage of this way is that it will be easy to replace activity with a fragment or a view. 这种方式的另一个优点是可以很容易地用片段或视图替换活动。
Edit 1: 编辑1:
Morgwai said this way will break separation of concern and single responsibility, but you cannot have single responsibility every where. Morgwai说这种方式会打破关注和单一责任的分离,但你不可能在每个地方都有单一的责任。 Sometime you need to violate it.
有时你需要违反它。 Here is an example from Google for MVP:
以下是Google针对MVP的示例:
TaskDetailPresenter
calls ShowEditTask
which is responsible to open a new Activity
inside TaskDetailFragment
. TaskDetailPresenter
调用ShowEditTask
,它负责在TaskDetailFragment
打开一个新的Activity
。
But also you can use CommandPattern which is a better approach 但是你也可以使用CommandPattern ,这是一种更好的方法
interface NavigationCommand {
void navigate();
}
So, Presenter will use it when it needs. 因此,Presenter将在需要时使用它。
As I wrote in my comment to the accepted answer , I think that managing navigation from the view layer is a clear breaking of separation of concerns rule: views should contain ONLY methods to update current UI screen. 正如我在对已接受答案的评论中所写的那样,我认为从视图层管理导航是明确打破关注点分离规则:视图应该只包含更新当前UI屏幕的方法。
The problem originates from the android platform design as Activity
and Fragment
classes contain both methods to operate on UI screen and to send intent objects that start other activities like startActivity
. 问题源于android平台设计,因为
Activity
和Fragment
类包含在UI屏幕上操作的方法以及发送启动其他活动(如startActivity
intent对象。
A clean way to solve this would be to create some Navigator
interface that would contain methods related to navigation, make activities implement it and inject it into presenters as well. 解决这个问题的一种简洁方法是创建一些
Navigator
接口,该接口将包含与导航相关的方法,make活动实现它并将其注入到演示者中。 This way at least from the presenters' standpoint navigation and UI manipulation would be separated. 这种方式至少可以从演示者的立场导航和UI操作中分离出来。 It may however look odd from activities' standpoint: now they would often implement both interfaces (Navigator and View) and pass their reference 2 times to the presenter.
然而,从活动的角度来看,它可能看起来很奇怪:现在他们经常实现两个接口(Navigator和View)并将它们的引用传递给演示者2次。 If because of this reason you decide to manage navigation from your view layer then at least keep methods for navigating separate from those for manipulating UI: never perform navigation and UI manipulation in the same method.
如果由于这个原因您决定从视图层管理导航,那么至少将导航方法与操作UI的方法分开:永远不要在同一方法中执行导航和UI操作。
In my opinion it would be better if you open an activity from the View Layer. 在我看来,如果你从视图层打开一个活动会更好。 I prefer that Presenter knows about Activity as little as possible.
我更喜欢Presenter尽可能少地了解Activity。
If there is some condition of what activity should be started, you can use something like this: 如果存在应该启动哪些活动的某些条件,您可以使用以下内容:
public class Presenter {
private ViewsPresentation mViewsPresentation;
public void someButtonClicked() {
if (/*some condition*/) {
mViewsPresentation.startFirstActivity();
} else {
mViewsPresentation.startSecondActivity();
}
}
public interface ViewsPresentation {
void startFirstActivity();
void startSecondActivity();
}
}
I have made this solution (in Kotlin):我已经做了这个解决方案(在 Kotlin 中):
I created an Interface called ViewNavigator我创建了一个名为 ViewNavigator 的界面
interface ViewNavigator {
fun navigateTo(target: Class<*>)
}
Then I made the View Interface Implement it然后我让视图接口实现它
interface View : ViewNavigator {
//...
}
Then the Actual View (the activity) can override the navigateTo
function然后实际视图(活动)可以覆盖
navigateTo
函数
override fun navigateTo(target: Class<*>) {
startActivity(Intent(this, target))
}
So, whenever I want to navigate to any activity, I can simply write that in the presenter class.因此,无论何时我想导航到任何活动,我都可以简单地将其写在演示者类中。 For example:
例如:
override fun onAnimationFinished() {
view.navigateTo(HomeActivity::class.java)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.