web-dev-qa-db-ja.com

Android PresenterからのMVPオープンアクティビティ、アンチパターン?

プレゼンターレイヤーからActivityを開くと、アンチパターンになりますか?

その場合、View Layerからアプリのナビゲーションを管理する必要がありますか?

32
Jose M Lechon

はい、それはアンチmvpパターンです。 MVPの パッシブビュー に基づいて、プレゼンターでAndroidフレームワークを扱う必要がないため、テスト容易性が失われました。

そのため、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();
    }
} 

また、この方法の別の利点は、アクティビティをフラグメントまたはビューに簡単に置き換えることができることです。

編集1:

Morgwai この方法は懸念と単一の責任の分離を壊すと言いましたが、どこでも単一の責任を持つことはできません。いつかあなたはそれに違反する必要があります。 MVP用のGoogleの例を次に示します。

TaskDetailPresenter を呼び出します ShowEditTaskActivity内で新しいTaskDetailFragmentを開く役割を果たします。

しかし、あなたは CommandPattern を使用することもできます。これはより良いアプローチです

interface NavigationCommand {
    void navigate();
}

そのため、Presenterは必要なときに使用します。

37
Saeed Masoumi

accepted answer へのコメントで書いたように、ビューレイヤーからのナビゲーションの管理は、懸念の分離ルールの明確な破れだと思います。ビューには、現在のUI画面を更新するメソッドのみを含める必要があります。

この問題は、Androidプラットフォーム設計に起因します。ActivityおよびFragmentクラスには、UI画面で操作するためのメソッドと、他のアクティビティを開始するインテントオブジェクトを送信するためのメソッドstartActivity

これを解決するためのクリーンな方法は、ナビゲーションに関連するメソッドを含むNavigatorインターフェイスを作成し、アクティビティに実装してプレゼンターにもインジェクトすることです。この方法では、少なくともプレゼンターの観点からのナビゲーションとUI操作は分離されます。しかし、アクティビティの観点からは奇妙に見えるかもしれません。今では、多くの場合、両方のインターフェイス(NavigatorとView)を実装し、参照をプレゼンターに2回渡します。このため、ビューレイヤーからナビゲーションを管理する場合は、少なくともUIを操作するためのメソッドとは別のナビゲーション用のメソッドを保持します。同じメソッドでナビゲーションとUI操作を実行しないでください。

9
morgwai

私の意見では、ビューレイヤーからアクティビティを開くとよいでしょう。プレゼンターはアクティビティについてできるだけ少ししか知らないことを好みます。

どのアクティビティを開始すべきかの条件がある場合、次のようなものを使用できます。

public class Presenter {

    private ViewsPresentation mViewsPresentation;

    public void someButtonClicked() {
        if (/*some condition*/) {
            mViewsPresentation.startFirstActivity();
        } else {
            mViewsPresentation.startSecondActivity();
        }
    }

    public interface ViewsPresentation {
        void startFirstActivity();
        void startSecondActivity();
    }

}
6
Alexander