【问题标题】:In MVP is onClick responsibility of View or Presenter?在 MVP 中,onClick 是 View 还是 Presenter 的责任?
【发布时间】:2018-04-21 20:39:23
【问题描述】:

在 MVP 模式中,谁负责处理 UI 上的点击?
例如。非 MVP 方法类似于:

counterButton.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
      totalClicks++;
      counterTextView.setText("Total clicks so far: "+totalClicks);
    }
  });

使用MVP是onClick的责任Presenter?或者View 可以处理吗?
有人可以澄清一下吗?

【问题讨论】:

    标签: java android mvp


    【解决方案1】:

    OnClick 应该调用Presenter 方法。您应该在 Presenter 中开展业务,如果您需要更新用户界面,您应该在 View 中定义一个方法并从 Presenter 中调用它。

    您需要为您的View 提供方法:

    public void showCounterCount(final int totalClicks){
         counterTextView.setText("Total clicks so far: "+totalClicks);
    }
    

    您的Presenter 中还需要一个方法和一个变量:

    int totalClicks = 0;
    
    public void onCounterButtonClicked(){
        totalClicks++;
        mView.showCounterCount(totalClicks);
    }
    

    然后像这样重构你的代码:

    counterButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          mPresenter.onCounterButtonClicked();
        }
      });
    

    对于更复杂和更简洁的架构,您可以在交互器中开展您的用例业务。 (在您的示例中,递增计数器值是您的应用程序的一个用例)

    您可以定义一个交互器并在那里增加您的计数器值。

    CounterInteractor:

    public CounterInteractor{
       public int incrementCounter(int currentCounter){
           return currentCounter+1;
       }
    }
    

    然后重构您的演示者,如下所示:

    int totalClicks = 0;
    CounterInteractor mCounterInteractor = new CounterInteractor();
    
    public void onCounterButtonClicked(){
        totalClicks = mCounterInteractor.incrementCounter(totalClicks);
        mView.showCounterCount(totalClicks);
    }
    

    通过这种方法,您可以将业务逻辑与演示者完全分开,并重新使用您的用例概念,而无需在演示者中复制代码。这是更干净的方法。

    您还可以查看此 git 存储库以了解不同的 MVP 方法。 https://github.com/googlesamples/android-architecture/tree/todo-mvp-clean/

    祝你好运。

    编辑:

    这是我的轻量级维基百科客户端项目源: https://github.com/savepopulation/wikilight

    我正在尝试实现MVP。 (MVP + Dagger2 + RxJava)

    【讨论】:

    • 老实说,如果这是 MVP 方法,我并不认为它比原来的 sn-p 有所改进。我们刚刚添加了 1 个抽象/重定向,但好处在哪里?
    • 我们把app分成三层,把业务逻辑和ui分开。活动和片段是视图,只负责更新 ui,只包含由演示者调用的接口方法。您的示例非常简单,因此很难看到好处,但在大型应用程序中您可以更清楚地看到它。它对 ui 测试也很有用。你可以检查这个链接。 antonioleiva.com/mvp-android
    • 一个主要的好处是测试。在上面的示例中,您可以在 Presenter 中为 onCounterButtonClicked() 方法编写单元测试,而不依赖于 Android 框架。此类测试可以在 JVM 上运行。顺便说一句,我在我的 Presenter 方法名称中避免使用诸如 button 和 click 之类的词,以不那么紧密地将它们与视图层的概念联系起来
    • 如果我有 4 个按钮会发生什么,我应该实现类似 mPresenter.onclick(buttonView) 还是类似 if (ButtonView.getId() == loggingButon.getId(){mPresenter.onloginclick}否则如果 (.......)
    • @JeCuRo 嗨,对不起,我的回答迟了。我认为如果您的按钮执行完全不同的操作,您应该实现 4 种不同的演示者方法并从视图中调用它们。将 android 视图组件传递给演示者(按钮等)不适合 mvp,因为您的演示者必须独立于 android sdk 进行测试。
    【解决方案2】:

    在 MVP 中,View 的职责是知道如何捕获点击,而不是决定在其上做什么。一旦 View 捕获到点击,它必须调用 Presenter 中的相关方法对其进行操作:

    --------------------查看--------

    button1.setOnClickListener(new OnClickListener({
    presenter.doWhenButton1isClicked();
    }));
    

    ----------------- 演示者----------------

    public void doWhenButton1isClicked(){
    // do whatever business requires
    }
    

    我有一系列关于 android 架构模式的文章,part 3 其中是关于 MVP 的。您可能会发现它很有帮助。

    【讨论】:

    • 如果它是 recyclerview 中的项目而不是按钮怎么办。将视图的引用传递给演示者是否正确,例如presenter.onCardViewClick(cardView); ?还有点击cardView时如何处理新的Intent?
    • @Adi,不,您不需要将视图元素传递给演示者。最终在任何视图元素上完成的任何事情都应由视图完成,那么为什么演示者可以访问它呢?因此,在您的情况下,您应该调用“presenter.onCardViewClick()”(不带参数)。对于 New Intent,您将 onclick 传递给 Presenter,如上所述,然后 Presenter 在视图中调用一个方法,例如处理新 Intent 的“view.goToNewActivity()”。因此,您执行意图的方式是在 View 内的方法中处理的。
    • 在我的例子中,为了新的意图,我需要从卡片视图中提取 userId 以显示用户配置文件。基本上,点击卡片视图没有相同的结果。我认为我需要做的最起码是presenter.onCardViewClick(String userId)。但是,这感觉就像将业务逻辑放在视图中一样。你的想法是什么?
    • @Adi,将 userId 或任何其他数据从视图传递给演示者以执行任何业务需求,这是正确的方式,并且与在视图层中执行业务逻辑不同。例如,如果您想在视图中按 userId 获取用户配置文件,这将把逻辑放在视图中。但是,您不会通过将 userId 传递给 Presenter 来执行任何业务逻辑。相反,演示者负责对这些数据执行的任何操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多