web-dev-qa-db-ja.com

Fragment内にMVP Presenterを登録できますか

Google が提供するMVPデザインパターンに従って、アプリケーションをリファクタリングしました。 MainActivityが1つとFragmentsが1つあり、フラグメントごとにアクティビティを作成するのは面倒ではないので、PresenterをFragmentに登録することを考えています。私が見ているのは、すべてのフラグメントが独自のプレゼンターを登録していることですが、それがどれほど間違っているのかわかりません... :)

私のプレゼンターは次のとおりです。

public class FirstPresenter implements FirstContract.Presenter {
    private final FirstContract.View mView;

    public FirstPresenter(FirstContract.View view) {
        mView = view;
    }

    @Override
    public void start() {
        Log.e(TAG, "Start");
    }
}

そして、これが私の断片です:

public class FirstFragment extends Fragment implements FirstContract.View {
    private FirstContract.Presenter mPresenter;

@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container
            , Bundle savedInstanceState) {
...
// I register firstFragment's presenter here.
mPresenter = new FirstPresenter(this);
...

私の質問は、これは正しい方法ですか? Activityの代わりにPresenterをFragmentに登録できますか?それが正しい方法ではない場合、1つのアクティビティと複数のフラグメントでMVPを処理する良い例はありますか?

皆さん、ありがとう!

12
MilanNz

Googleのサンプル( https://github.com/googlesamples/Android-architecture )でわかるように、Activities create Presenters。また、ViewsActivityに接続し、Presentersをパラメーターとしてビュー(Fragments)を取得します。

Fragmentトランザクションがコミットされた後、またはFragment(ビュー)状態が復元された後Presentersが作成され、呼び出しとしてパラメーターとしてFragments(ビュー)を取ります

view.setPresenter(T presenter); 

ビューのメソッドとPresentersがビューに登録されます。

PresenterFragmentを作成することはお勧めできません。まず第一に、それらは別々のレイヤーです。これは、懸念事項の分離には違法です。次に、Fragmentでプレゼンターを作成する場合、プレゼンターのライフをビューのLifeCycleにバインドし、Fragmentを破棄して再作成すると、新しいプレゼンターを作成しますが、異なる層。

modelは、表示されるデータ、またはユーザーインターフェイスで処理されるデータを定義するインターフェイスです。

プレゼンターはモデルとビューに作用します。リポジトリ(モデル)からデータを取得し、ビューに表示するためにフォーマットします。

viewは、データ(モデル)を表示し、ユーザーコマンド(イベント)をプレゼンターにルーティングしてそのデータに基づいて行動するパッシブインターフェイスです。

したがって、Activityoverall controllerは、PresentersViewsを作成し、それらを接続します。

enter image description here

あなたの質問について話すならば、はい、あなたは発表者を断片的に登録することができます。ただし、ビューとして使用するフラグメントにプレゼンターを作成することは避けてください。

ただし、Android以下のようなコミュニティ。MVPパターンに関するさまざまなアプローチがあります。 https://plus.google.com/communities/114285790907815804707

アクティビティがUI要素ではないのはなぜですか? http://www.techyourchance.com/activities-Android/

18
savepopulation

単一のアクティビティを使用して複数のフラグメントをホストし、Dagger 2を使用してプレゼンターを注入する場合は、各プレゼンターを各フラグメントに直接注入できます。

私のユースケースストーリー

Android jetpack Navigation Componentを見つけてから、数か月前からアーキテクチャを使用してプロジェクトを行っています。すべてのアプリビューをこのパターンに移行し始めました。

だから、私はプロセスを行う多くのリファクタリングに遭遇し、この状況で何をすべきかわからないというこの状況にいました。

開始点からDagger 2を使用してプレゼンターをアクティビティに挿入したため、これはフラグメントを使用した場合と同じように変更されません。

同じリポジトリを見つけて、フラグメントがどのようにアーキテクチャに追従するかを確認しました。これは、子としてフラグメントが1つしかない場合に、ホストアクティビティ内でプレゼンターのインスタンス化を実行する良い方法です。

1つのホストアクティビティ内に複数のフラグメントを含める必要がある場合、各プレゼンターのインスタンスを作成し、各フラグメント内のFragmentManagerを介して渡す必要があり、複数のインスタンス化を追加するため、私は見ていなかったと思いますホストアクティビティのプレゼンター。

これにより、すべてのプレゼンターのHostアクティビティ内に複数のインスタンスがあり、必要に応じてジョブ/ビューのデタッチを処理するためのいくつかのインターフェイスを持つ、1つのケースが発生します。

複数のフラグメントを使用する簡単な方法の1つは、ホストアクティビティを考えずに、各フラグメント自体にプレゼンターを挿入することです。

これをDaggerで行うため、注入がよりクリーンになります。

簡単な例を見てみましょう

_class MainMenuActivity : BaseActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        inflateMainFragment(savedInstanceState)
    }

      override fun getLayout(): Int {
        return R.layout.activity_main_menu
    }

    fun inflateMainFragment(savedInstanceState: Bundle?){
        if (savedInstanceState == null) {
            val fragment = MainMenuFragment()
            supportFragmentManager
                .beginTransaction()
                .add(R.id.nav_Host_fragment, fragment)
                .commit()
        }
    }
}
_

ご覧のとおり、ここでは、ナビゲーションに必要なプレゼンターのインスタンスを作成しません。代わりに、必要な各プレゼンターを各フラグメント内に注入するだけです

_class MapsFragment: BaseMapFragment(), MapContract.MapView {

    private lateinit var mMap: GoogleMap

    @Inject
    lateinit var presenter: MapsPresenter

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_paseo,container,false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (requireActivity().application as YawpApplication).getAppComponent()?.inject(this)
        presenter.attachView(this)
        setupToolbar()
        setupMap()
    }
}
_

また、フラグメントライフサイクルを利用して、onDestroyView()メソッドですべてのフラグメントビューをデタッチし、ガベージコレクターの実行時にメモリスペースを節約することもできます。

_ override fun onDestroyView() {
        super.onDestroyView()
        presenter.detachView()
        presenter.detachJob()
    }
_

公式のgoogleレポジトリで、よりよく理解するのに役立つ質問を見つけました。

確認できます こちら

1