web-dev-qa-db-ja.com

Android MVP-アクティビティプレゼンターとフラグメントプレゼンター間の通信方法

3つのフラグメントを持つアクティビティーがあり、現在はViewPagerを使用しています。 MVPを実装し、アクティビティプレゼンターとフラグメントプレゼンターの間で通信したい:

  • アクティビティプレゼンターからフラグメントプレゼンターにデータを渡す
  • フラグメントプレゼンターからアクティビティプレゼンターへのイベントの送信
  • ...

しかし、私はそれを公式に行う方法を知りません。 BusEventを使用することはできますが、良い方法ではないと思います。

27
Norutan

フラグメントとアクティビティの間の通信、またはその逆は nnn's answer を使用して行うことができます。またはViewModelおよびLiveDataを使用して、よりクリーンな方法でライフサイクルを尊重できます。 fragmentsactivitiesを使用すると、非表示のfragmentがバックグラウンドでデータを受信しないようにするために、数行のコードを書く必要がなくなります。

まず、ViewModelクラスを拡張し、Livedataといくつかのヘルパーメソッドを初期化します。

_public class MyViewModel extends ViewModel {
private MutableLiveData<String> toFragmentA, toFragmentB;
private MutableLiveData<List<String>>  toAllFragments;

public MyViewModel() {
    toFragmentA = new MutableLiveData<>();
    toFragmentB = new MutableLiveData<>();
    toAllFragments = new MutableLiveData<>();
}

public void changeFragmentAData(String value){
    toFragmentA.postValue(value);
}
public void changeFragmentBData(String value){
    toFragmentB.postValue(value);
}
public void changeFragmentAllData(List<String> value){
    toAllFragments.postValue(value);
}

public LiveData<String> getToFragmentA() {
    return toFragmentA;
}

public LiveData<List<String>> getToAllFragments() {
    return toAllFragments;
}

public LiveData<String> getToFragmentB() {
    return toFragmentB;
}
_

}

次に、アクティビティでViewModelを初期化します。

_public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private TabLayout tabLayout;
MyViewModel mViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mViewModel = ViewModelProviders.of(this)
            .get(MyViewModel.class);

    viewPager.setAdapter(new Adapter(getSupportFragmentManager()));


}
_

}

フラグメントのデータを読み取る:

_ @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

    mViewModel.getToAllFragments().observe(this, new Observer<List<String>>() {
        @Override
        public void onChanged(List<String> s) {
            myList.addAll(s);
            //do something like update a RecyclerView
        }
    });

    mViewModel.getToFragmentA().observe(this, new Observer<String>() {


        @Override
        public void onChanged(String s) {
            mytext = s;
            //do something like update a TextView
        }
    });
}
_

ライブデータの値を変更するには、フラグメントまたはアクティビティでメソッドの1つを使用できます。

_changeFragmentAData();
changeFragmentBData();
changeFragmentAllData();
_

舞台裏で何が起こっている

mViewModel = ViewModelProviders.of(this).get(MyViewModel.class)を使用する場合、ViewModelのインスタンスを作成し、それをフラグメントの特定のアクティビティのライフサイクルにバインドして、ビューモデルがactivityまたはfragementは停止しています。 mViewModel = ViewModelProviders.of(getActivity())。get(MyViewModel.class)_you are bindig it to the lifecycle if the parent_ activity`を使用する場合

mViewModel.getToFragmentA().observe()またはmViewModel.getToFragmentB().observe()またはmViewModel.getToAllFragments().observe()を使用する場合、LiveDataクラスのMyViewModelを特定のフラグメントまたはアクティビティに接続しますonChange()メソッドの値は、メソッドを監視しているすべてのクラスで更新されます。

私はLivedata end ViewModelについて少し調査することをお勧めします youtube または this link

3
sutuioncode

私の理解では、UseCaseについて、ActivityAに3つのフラグメント(FragmentA、FragmentB、FragmentC)を持つviewPagerがあるとします。

ActivityAにはActivityPresenterAがあります

FragmentAにはFragmentPresenterAがあります

MVPに従って、FragmentPresenterAはFragmentAのすべての論理フローとビジネスフローに対してのみ責任を負い、FragmentAとのみ通信する必要があります。したがって、FragmentPresenterAはActivityPresenterAと直接通信できません。

FragmentからActivityへの通信では、プレゼンターは関与しないでください。これは、MVP以外のアーキテクチャで通信する場合と同様に、つまりインターフェースを使用して行う必要があります。

同じことが、アクティビティとフラグメントの通信にも当てはまります。

アクティビティとフラグメント間の通信については ここ をお読みください

1
nnn

その場合、1人のプレゼンターを使用できます。

アクティビティプレゼンターを使用して、フラグメントに必要なすべてのデータを取得しました。次に、インターフェースクラスを作成し、フラグメントに実装します。

例:

PageAFragmentのパブリックインターフェイスを作成します(このインターフェイスは、アクティビティからフラグメントへのデータのブリッジになります)。インターフェースのメソッドを使用して、プレゼンターからの結果を処理して表示します。

これは、受信データ用に作成したインターフェースクラスの例です。パラメータは必要に応じて選択できますが、私はモデルを選択します。

public interface CallbackReceivedData {
    void onDataReceived(YourModel model);
}

MainActivity Classで、アクティビティにアタッチされたフラグメントのインスタンスを確認します。フラグメントをコミットした後、チェックインスタンスを配置します。

public class MainActivity extends AppCompatActivity{

  private CallbackReceivedData callbackReceivedData;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      //after commit the fragment
    if (fragment instanceof PageAFragment){
            callbackReceivedData = (CallbackReceivedData)fragment;
    }

  }
  //this is the example method of MainActivity Presenter, 
  //Imagine it, as your view method.
  public void receivedDataFromPresenter(YourModel model){
      callbackReceivedData.onDataReceived(model);
  }

}

receivedDataFromPresenterがビューの受信メソッドであり、プレゼンターにデータを取得すると想定しました。

次に、プレゼンターからcallbackReceivedDataにデータを渡します

PageAFragmentCallbackReceivedDataを実装し、onDataReceivedメソッド。これで、アクティビティからフラグメントにデータを渡すことができます。

public class PageAFragment extends Fragment implements CallbackReceivedData{

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public void onDataReceived(YourModel model) {

    }
}

注:別の方法として、バンドルを使用し、setArgumentsを使用してデータを渡すことができます。

FragmentからActivityにイベントを送信する場合は、このアイデアに従うことができます。

インターフェースクラスを作成してMainActivityに実装し、インターフェースからアクティビティにメソッドをオーバーライドします。私の場合は、次のようにします。

これが私のCallbackSendData Classです。

public interface CallbackSendData {
    void sendDataEvent(String event);
}

CallbackSendDataインターフェースをMainActivityに実装し、sendDataEventメソッド。

public class MainActivity extends AppCompatActivity implements CallbackSendData{

  private CallbackReceivedData callbackReceivedData;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

     //after commit the fragment
     if (fragment instanceof PageAFragment){
         callbackReceivedData = (CallbackReceivedData)fragment;
     }

  }

  //this is the example method of MainActivity Presenter, 
  //Imagine it, as your view method.
  public void receivedDataFromPresenter(YourModel model){
      callbackReceivedData.onDataReceived(model);
  }    


  @Override
  public void sendDataEvent(String event){
     //You can now send the data to your presenter here.
  }



}

そして、あなたのPageAFragmentに対して、あなたはあなたのインターフェースをキャストするためにattachメソッドを使う必要があります。フラグメントがそのアクティビティに関連付けられると、attachメソッドが呼び出されます。フラグメントのライフサイクルを理解したい場合は、次のリンクをクリックしてください: https://developer.Android.com/reference/Android/app/Fragment.html

public class PageAFragment extends Fragment implements CallbackReceivedData{

    private CallbackSendData callbackSendData;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }

    @Override
    public void onDataReceived(YourModel model) {
        //Received the data from Activity to Fragment here.
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 
    container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.PagerAFragment, container, 
    false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle 
    savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Button Eventbutton;

        Eventbutton = view.findViewById(R.id.event_button);
        Eventbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                callbackSendData.sendDataEvent("send Data sample");
            }
        });
    }

   @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            callbackSendData = (CallbackSendData) context;
        }catch (ClassCastException e){
            e.printStackTrace();
        }
    }

}

そして、CallbackSendDataを使用して、アクティビティからフラグメントにデータを送信できます。

注:Dependency Injectionをプロジェクトに使用している場合は、はるかに簡単です。Dagger2ライブラリを使用できます。

グッドラック

0
Benidict Dulce

FragmentActivityの間で(プレゼンターまたはクラス間で)通信するには、アクティビティが実装するインターフェース(ShoppingInteractorなど)が必要です。

このようにして、フラグメントで_((ShoppingInteractor)getActivity()).doSomething()_を呼び出すことができます。アクティビティのプレゼンターにタスクを処理させたい場合は、アクティビティ内のdoSomethingでプレゼンターを呼び出す必要があります。

別のインターフェースを使用してフラグメントに対して同じことを行い、アクティビティー内でフラグメントのインタラクターを呼び出すことができます。

これらのインターフェース内にPresenter getPresenter()を入れて、実際のプレゼンターにアクセスすることもできます。 (_((ShoppingInteractor)getActivity()).getPresenter().sendData(data)_)。フラグメントについても同様です。

0
Adib Faramarzi

動的データ:

以下は、rxjava2、dagger2、およびmoxyを使用した例です。

条件:

  • プレゼンターはビューのライフサイクルに依存しません
  • 1人のプレゼンター-1つのビュー。ビューはプレゼンターを共有しません。1つのビューには1つのプレゼンターしかありません。

ソリューションはEventBusに似ていますが、代わりに有効期間が限定されたSubjectを使用します。これは、アクティビティの開始時に作成され、終了すると破棄されるコンポーネント内にあります。アクティビティとフラグメントはどちらも暗黙的にアクセスでき、値を変更して独自の方法でそれに応答できます。

サンプルプロジェクト: https://github.com/Anrimian/ViewPagerMvpExample

静的データ:

フラグメントで引数を使用するだけです。

0
Anrimian

MVPを使用する場合の最初のステップは、ビューごとに1つのプレゼンターを作成することです。つまり、フラグメントが3つある場合、プレゼンターは3つになります。 4つのビュー(アクティビティと3つのフラグメント)に対して1つのプレゼンターを作成するのは、悪い考えだと思います。

0
Victor