次のように、ターゲットフラグメントを設定するプロセスで、childFragmentManager
を使用してフラグメント内またはsupportFragmentManager
を使用してアクティビティ内にダイアログを表示しています。
val textSearchDialog = TextSearchDialogFragment.newInstance()
textSearchDialog.setTargetFragment(PlaceSearchFragment@this, 0)
しかし、そのコードを実行すると、エラーが発生します。
Java.lang.IllegalStateException:Fragment TextSearchDialogFragment {b7fce67#0 0}がこのFragmentManagerに属さないターゲットフラグメントPlaceSearchFragment {f87414#0 id = 0x7f080078}を宣言しました!
ナビゲーションコンポーネントがフラグメントの表示を管理するために使用しているFragmentManager
にアクセスする方法がわかりません。これに対する解決策はありますか?
ナビゲーションアーキテクチャコンポーネントを使用してフラグメント間で通信するための推奨パターンは、 shared ViewModel
-ViewModel
で、ViewModel
を使用してViewModelProviders.of(getActivity())
ドキュメント のとおり、これにはいくつかの利点があります。
- アクティビティは何もする必要がなく、この通信について何も知る必要はありません。
- フラグメントは、
SharedViewModel
コントラクト以外はお互いを知る必要はありません。片方のフラグメントが消えても、もう片方は通常どおり機能し続けます。- 各フラグメントには独自のライフサイクルがあり、他のフラグメントのライフサイクルの影響を受けません。 1つのフラグメントが他のフラグメントを置き換える場合、UIは問題なく機能し続けます。
受け入れられた回答について詳しく説明するには:
(1)そのアクティビティ内のフラグメント間でデータを共有するために使用される共有ビューモデルを作成します。
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Double> aDouble = new MutableLiveData<>();
public void setDouble(Double aDouble) {
this.aDouble.setValue(aDouble);
}
public LiveData<Double> getDouble() {
return aDouble;
}
}
(2)アクセスしたいデータをビューモデルに格納します。ビューモデル(getActivity)のスコープに注意してください。
SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.setDouble(someDouble);
(3)フラグメントにダイアログのコールバックインターフェースを実装させ、ターゲットフラグメントを設定せずにダイアログをロードします。
fragment.setOnDialogSubmitListener(this);
fragment.show(getActivity().getSupportFragmentManager(), TAG);
(4)ダイアログ内でデータを取得します。
SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.getDouble().observe(this, new Observer<Double>() {
@Override
public void onChanged(Double aDouble) {
// do what ever with aDouble
}
});
ビューモデルとフラグメントktxを使用すると、親フラグメントと子フラグメントの間で共有ビューモデルをホストできるため、アクティビティにビューモデルのインスタンスを含め、そのアクティビティが完了するまでデータを保存する代わりに、ビューモデルを親内に保存できますフラグメント、そうすることで、ビューモデルをインスタンス化したフラグメントをポップすると、ビューモデルがクリアされます
_implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
_
_class ParentFragment:Fragment() {
private val model: SharedViewModel by viewModels()
}
_
_class ChildFragment:Fragment(){
private val model: SharedViewModel by viewModels ({requireParentFragment()})
}
_
したがって、これを実行すると、親フラグメントでsharedviewmodelがホストされ、その親フラグメントに依存する子フラグメントは、SharedViewModel
の同じインスタンスにアクセスでき、ポップ(別名フラグメントの破棄)すると、onCleared()
メソッドがビューモデルで起動し、そのshareviewmodelがクリアされ、すべてのデータもクリアされます。
この方法では、フラグメントが共有するすべてのデータを含むMainActivityがなく、SharedViewModel
を使用するフラグメントを残すたびにそのデータをクリアする必要がありません。
アルファ版では、ナビゲーション間でデータを保存するビューモデルを使用して、ナビゲーション間でデータを渡すことができます。たとえば、フラグメントBとフラグメントAの間でデータを共有したい場合、2行で簡単に実行できます。
https://developer.Android.com/guide/navigation/navigation-programmatic#returning_a_result