web-dev-qa-db-ja.com

ナビゲーションコンポーネントの使用時にダイアログのターゲットフラグメントを設定する方法

次のように、ターゲットフラグメントを設定するプロセスで、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にアクセスする方法がわかりません。これに対する解決策はありますか?

13

ナビゲーションアーキテクチャコンポーネントを使用してフラグメント間で通信するための推奨パターンは、 shared ViewModel -ViewModelで、ViewModelを使用してViewModelProviders.of(getActivity())

ドキュメント のとおり、これにはいくつかの利点があります。

  • アクティビティは何もする必要がなく、この通信について何も知る必要はありません。
  • フラグメントは、SharedViewModelコントラクト以外はお互いを知る必要はありません。片方のフラグメントが消えても、もう片方は通常どおり機能し続けます。
  • 各フラグメントには独自のライフサイクルがあり、他のフラグメントのライフサイクルの影響を受けません。 1つのフラグメントが他のフラグメントを置き換える場合、UIは問題なく機能し続けます。
9
ianhanniballake

受け入れられた回答について詳しく説明するには:

(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
    }
}); 
2
Jeffrey

ビューモデルとフラグメントktxを使用すると、親フラグメントと子フラグメントの間で共有ビューモデルをホストできるため、アクティビティにビューモデルのインスタンスを含め、そのアクティビティが完了するまでデータを保存する代わりに、ビューモデルを親内に保存できますフラグメント、そうすることで、ビューモデルをインスタンス化したフラグメントをポップすると、ビューモデルがクリアされます

輸入

_implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
 implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
_

ParentFragment(SharedViewModelホスト)

_class ParentFragment:Fragment() {
 private val model: SharedViewModel by viewModels()
}
_

ChildFragment

_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

0