Navigation Component를 사용할 때 Fragment - Fragment, Fragment - DialogFragment 간에 결과값을 주고 받는 것은 위의 방법으로는 해결되지 않습니다. 님의 사용하신 코드는 결과값을 받는 것이 아니라 네비게이션 시에 데이터를 전달하는 코드로 다르다고 볼 수 있습니다. startActivityForResult를 생각해보시면 이해가 가실 겁니다.
자세한 방법은 https://developer.android.com/guide/navigation/navigation-programmatic 에 나와 있고, DialogFragment로 부터 결과값을 받으려면, 아래처럼 하시면 됩니다.
// DialogFragment
navController.previousBackStackEntry?.savedStateHandle?.set("key", result)
// DialogFragment로부터 응답을 기다리는 Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val navController = findNavController();
// After a configuration change or process death, the currentBackStackEntry
// points to the dialog destination, so you must use getBackStackEntry()
// with the specific ID of your destination to ensure we always
// get the right NavBackStackEntry
val navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment)
// Create our observer and add it to the NavBackStackEntry's lifecycle
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME
&& navBackStackEntry.savedStateHandle.contains("key")) {
val result = navBackStackEntry.savedStateHandle.get<String>("key");
// Do something with the result
}
}
navBackStackEntry.lifecycle.addObserver(observer)
// As addObserver() does not automatically remove the observer, we
// call removeObserver() manually when the view lifecycle is destroyed
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
navBackStackEntry.lifecycle.removeObserver(observer)
}
})
}
위의 코드를 Kotlin Extension function으로 만들면 편리합니다.
const val DIALOG_RESULT_KEY = "DialogResult"
inline fun <T> Fragment.getDialogNavResult(@IdRes navId: Int, key: String = DIALOG_RESULT_KEY, crossinline onChanged: (T?) -> Unit) {
val backStackEntry = findNavController().getBackStackEntry(navId)
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME && backStackEntry.savedStateHandle.contains(key)) {
val result = backStackEntry.savedStateHandle.get<T>(key)
onChanged(result)
backStackEntry.savedStateHandle.remove<T>(key)
}
}
backStackEntry.lifecycle.addObserver(observer)
viewLifecycleOwner.lifecycle.addObserver(
LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
backStackEntry.lifecycle.removeObserver(observer)
}
}
)
}
fun <T> Fragment.setNavResult(key: String = DIALOG_RESULT_KEY, data: T) {
findNavController().previousBackStackEntry?.also { stack ->
stack.savedStateHandle.set(key, data)
}
}
이제 위의 Extension function을 이용하여 다음과 같이 호출하면 됩니다.
// DialogFragment
viewModel.successAcceptData.observe(viewLifecycleOwner) {
val denied = it?.isEmpty() == true
binding.progressBar.isVisible = denied
if (denied) return@observe
Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show()
setNavResult(data = ACCEPTED)
findNavController().popBackStack()
}
// Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
getDialogNavResult<ACCEPTED데이터타입>(navId = R.id.your_fragment) { result ->
if (result == ACCEPTED) {
acceptAdapter.refresh()
}
}
}