简体   繁体   English

Android MVP 从 Presenter 打开 Activity,反模式?

[英]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平台设计,因为ActivityFragment类包含在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.

相关问题 Android MVP - 从活动展示器到片段展示器的数据 - Android MVP - Data from activity presenter to fragment presenter Android多态性:反模式? - Android Polymorphism: Anti-Pattern? 演示者在 Android MVP 模式中具有处理程序 - Presenter having Handler in Android MVP pattern Android MVP-活动应该是视图还是演示者? - Android MVP - should an Activity be a View or Presenter? Android MVP - 如何在活动演示者和片段演示者之间进行通信 - Android MVP - How to communicate between activity presenter and fragment presenter 我们是否需要用于Android MVP模式的登录以及Signup Activity的其他Presenter? - Do we need different Presenter for Login as well as Signup Activity in android MVP pattern? 在MVP模式下,Presenter应该是Android应用程序的活动性还是功能性 - In MVP pattern, should Presenter be activity-wise or functionality-wise of Android app 我们应该检查Presenter或MVP模式的Activity中的视图可见性吗? - Should we check for view visibility in Presenter or Activity in MVP pattern? 主持人是否知道MVP模式中的活动/上下文是个坏主意? - Does the presenter having knowledge of the Activity / Context a bad idea in the MVP pattern? Android Kotlin协程:使用Global范围是否是反模式? - Android Kotlin Coroutines: Is using Global scope an anti-pattern?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM