How to set target fragment of a dialog when using navigation components
To elaborate on the accepted answer:
(1) Create a shared view model that would be used to share data between fragments within that Activity.
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) Store the data you would like to access in the view model. Note the scope of the view model (getActivity).
SharedViewModel svm =ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
svm.setDouble(someDouble);
(3) Let the fragment implement the dialog's callback interface and load the dialog without setting a target fragment.
fragment.setOnDialogSubmitListener(this);
fragment.show(getActivity().getSupportFragmentManager(), TAG);
(4) Inside the dialog retrieve the data.
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
}
});
Update: as part of Navigation 2.3.0, Navigation adds explicit support for returning a result with a specific section on returning a result from a Dialog destination as an alternative to using a shared ViewModel.
Previous answer:
The recommended pattern for communicating between Fragments with the Navigation Architecture Components is via a shared ViewModel
- a ViewModel
that lives at the Activity level achieved by retrieving the ViewModel
using ViewModelProvider(getActivity())
As per the documentation, this offers a number of benefits:
- The activity does not need to do anything, or know anything about this communication.
- Fragments don't need to know about each other besides the
SharedViewModel
contract. If one of the fragments disappears, the other one keeps working as usual.- Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.
You can also share ViewModels at a smaller scope than your whole activity by using a navigation graph scoped ViewModel.
With viewmodel and fragment ktx, you can host a shared viewmodel between a parent fragment and a child fragment, so instead of having your activity contain the instance of the viewmodel and storing the data until that activity finishes, you can store the viewmodel within the parent fragment, doing so, when you pop the fragment that instantiated the viewmodel, the viewmodel will be cleared
Imports
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
ParentFragment (SharedViewModel host)
class ParentFragment:Fragment() {
private val model: SharedViewModel by viewModels()
}
ChildFragment
class ChildFragment:Fragment(){
private val model: SharedViewModel by viewModels ({requireParentFragment()})
}
So, doing this will host the sharedviewmodel in the parent fragment, and the child fragment depending on that parent fragment will have access to that same instance of the SharedViewModel
and when you pop (aka destroying the fragment) , your onCleared()
method will fire at your viewmodel and that shareviewmodel will be cleared, and also all it's data.
This way, you don't have your MainActivity to contain all the data that fragments share, and you don't need to clear that data each time you leave a fragment that uses the SharedViewModel
Now in alpha, you can pass data between navigations using also a viewmodel that will save the data between navigations, lets say you want to share data between Fragment B and fragment A, now you can do it simply with two lines
https://developer.android.com/guide/navigation/navigation-programmatic#returning_a_result