3つのフラグメントを持つアクティビティーがあり、現在はViewPagerを使用しています。 MVPを実装し、アクティビティプレゼンターとフラグメントプレゼンターの間で通信したい:
しかし、私はそれを公式に行う方法を知りません。 BusEventを使用することはできますが、良い方法ではないと思います。
フラグメントとアクティビティの間の通信、またはその逆は nnn's answer を使用して行うことができます。またはViewModel
およびLiveData
を使用して、よりクリーンな方法でライフサイクルを尊重できます。 fragments
とactivities
を使用すると、非表示の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
私の理解では、UseCaseについて、ActivityAに3つのフラグメント(FragmentA、FragmentB、FragmentC)を持つviewPagerがあるとします。
ActivityAにはActivityPresenterAがあります
FragmentAにはFragmentPresenterAがあります
MVPに従って、FragmentPresenterAはFragmentAのすべての論理フローとビジネスフローに対してのみ責任を負い、FragmentAとのみ通信する必要があります。したがって、FragmentPresenterAはActivityPresenterAと直接通信できません。
FragmentからActivityへの通信では、プレゼンターは関与しないでください。これは、MVP以外のアーキテクチャで通信する場合と同様に、つまりインターフェースを使用して行う必要があります。
同じことが、アクティビティとフラグメントの通信にも当てはまります。
アクティビティとフラグメント間の通信については ここ をお読みください
その場合、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にデータを渡します
PageAFragmentでCallbackReceivedDataを実装し、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ライブラリを使用できます。
グッドラック
Fragment
とActivity
の間で(プレゼンターまたはクラス間で)通信するには、アクティビティが実装するインターフェース(ShoppingInteractor
など)が必要です。
このようにして、フラグメントで_((ShoppingInteractor)getActivity()).doSomething()
_を呼び出すことができます。アクティビティのプレゼンターにタスクを処理させたい場合は、アクティビティ内のdoSomething
でプレゼンターを呼び出す必要があります。
別のインターフェースを使用してフラグメントに対して同じことを行い、アクティビティー内でフラグメントのインタラクターを呼び出すことができます。
これらのインターフェース内にPresenter getPresenter()
を入れて、実際のプレゼンターにアクセスすることもできます。 (_((ShoppingInteractor)getActivity()).getPresenter().sendData(data)
_)。フラグメントについても同様です。
動的データ:
以下は、rxjava2、dagger2、およびmoxyを使用した例です。
条件:
ソリューションはEventBusに似ていますが、代わりに有効期間が限定されたSubjectを使用します。これは、アクティビティの開始時に作成され、終了すると破棄されるコンポーネント内にあります。アクティビティとフラグメントはどちらも暗黙的にアクセスでき、値を変更して独自の方法でそれに応答できます。
サンプルプロジェクト: https://github.com/Anrimian/ViewPagerMvpExample
静的データ:
フラグメントで引数を使用するだけです。
MVPを使用する場合の最初のステップは、ビューごとに1つのプレゼンターを作成することです。つまり、フラグメントが3つある場合、プレゼンターは3つになります。 4つのビュー(アクティビティと3つのフラグメント)に対して1つのプレゼンターを作成するのは、悪い考えだと思います。