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

时间:2016-04-28 10:40:03

标签: android mvp

如果从Presenter图层打开Activity,它会是反模式吗?

如果是这样,我应该从视图层管理应用程序的导航吗?

4 个答案:

答案 0 :(得分:34)

是的,它是一种反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();
    }
} 

这种方式的另一个优点是可以很容易地用片段或视图替换活动。

修改1:

Morgwai说这种方式会打破关注和单一责任的分离,但你不可能在每个地方都有单一的责任。有时你需要违反它。以下是Google针对MVP的示例:

TaskDetailPresenter致电ShowEditTask,负责在Activity内开设新的TaskDetailFragment

但你也可以使用CommandPattern这是一种更好的方法

interface NavigationCommand {
    void navigate();
}

因此,Presenter会在需要时使用它。

答案 1 :(得分:9)

As I wrote in my comment to the accepted answer,我认为从视图层管理导航明显打破了关注点分离规则:视图应该仅包含更新当前UI屏幕的方法。

问题源于android平台设计,aActivity类包含在UI屏幕上操作的方法,以及发送启动其他活动的意图对象,如Fragment

解决这个问题的一个简洁方法是创建一些startActivity接口,该接口将包含与导航相关的方法,make活动实现它并将其注入到演示者中。这种方式至少来自主持人'立场导航和UI操作将分开。然而,从活动中可能看起来很奇怪。立场:现在他们经常实现两个接口(Navigator和View)并将他们的引用传递给演示者2次。如果由于这个原因你决定从视图层管理导航,那么至少保持导航方法与操纵UI的方法分开:永远不要在同一方法中执行导航和UI操作。

答案 2 :(得分:5)

在我看来,如果从View Layer打开一个活动会更好。我更喜欢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();
    }

}

答案 3 :(得分:0)

我已经解决了这个问题(在Kotlin中):
我创建了一个名为ViewNavigator的接口

interface ViewNavigator {
    fun navigateTo(target: Class<*>)
}

然后我让View Interface实施

interface View : ViewNavigator {
    //...
}

然后实际视图(活动)可以覆盖navigateTo函数

override fun navigateTo(target: Class<*>) {
    startActivity(Intent(this, target))
}

因此,每当我想导航到任何活动时,都可以将其简单地写在presenter类中。例如:

override fun onAnimationFinished() {
    view.navigateTo(HomeActivity::class.java)
}