我们说我们有两个片段:MainFragment
和SelectionFragment
。第二个是用于选择某个对象的构建,例如整数。从第二个片段接收结果有不同的方法,如回调,总线等。
现在,如果我们决定使用导航架构组件导航到第二个片段,我们可以使用此代码:
NavHostFragment.findNavController(this).navigate(R.id.action_selection, bundle)
其中bundle
是Bundle
的实例(当然)。正如您所看到的,我们无法访问SelectionFragment
我们可以进行回调。问题是,如何使用Navigation Architecture Component接收结果?
答案 0 :(得分:46)
他们在2.3.0-alpha02版本中添加了fix for this。
如果从片段A 导航到片段B 和 A ,则需要 B 的结果:
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Type>("key")?.observe(viewLifecycleOwner) {result ->
// Do something with the result.
}
如果在片段B 上并且需要设置结果:
findNavController().previousBackStackEntry?.savedStateHandle?.set("key", result)
我最终为此创建了两个扩展名:
fun Fragment.getNavigationResult(key: String = "result") =
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>(key)
fun Fragment.setNavigationResult(result: String, key: String = "result") {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, result)
}
答案 1 :(得分:25)
自片段KTX 1.3.0-alpha04起,Android支持在片段之间或片段与活动之间传递数据。它类似于startActivityForResult
逻辑。
这是导航组件的示例。您可以详细了解here
build.gradle
implementation "androidx.fragment:fragment-ktx:1.3.0-alpha04"
FragmentA.kt
class FragmentA : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// Step 1. Listen for fragment results
setFragmentResultListener(FragmentB.REQUEST_KEY) { key, bundle ->
// read from the bundle
}
// Step 2. Navigate to Fragment B
findNavController().navigate(R.id.fragmentB)
}
}
FragmentB.kt
class FragmentB : Fragment() {
companion object {
val REQUEST_KEY = "FragmentB_REQUEST_KEY"
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
buttonA.setOnClickListener { view ->
// Step 3. Set a result
setFragmentResult(REQUEST_KEY, bundleOf("data" to "button clicked"))
// Step 4. Go back to Fragment A
findNavController().navigateUp()
}
}
}
答案 2 :(得分:9)
谷歌:you should try to use shared ViewModel。请查看以下Google的示例:
共享ViewModel ,它将包含共享数据,可以从不同的片段进行访问。
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
更新ViewModel的MasterFragment:
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
使用共享ViewModel的DetailsFragment:
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item -> {
// Update the UI.
});
}
}
答案 3 :(得分:5)
使用这些扩展功能
fun <T> Fragment.getNavigationResult(key: String = "result") =
findNavController().currentBackStackEntry?.savedStateHandle?.get<T>(key)
fun <T> Fragment.getNavigationResultLiveData(key: String = "result") =
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)
fun <T> Fragment.setNavigationResult(result: T, key: String = "result") {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, result)
}
因此,如果您要将结果从片段 B 发送到片段 A
内部片段 B
setNavigationResult(false, "someKey")
内部片段 A
val result = fragment.getNavigationResultLiveData<Boolean>("someKey")
result.observe(viewLifecycleOwner){ booleanValue-> doSomething(booleanValue)
答案 4 :(得分:1)
对@LeHaine的答案进行了一些改进,您可以将这些方法用于2.3.0-alpha02
及更高版本的导航
fun <T> Fragment.getNavigationResult(key: String) =
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)
fun <T> Fragment.setNavigationResult(result: T, key: String) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, result)
}
答案 5 :(得分:0)
我建议您使用NavigationResult库,它是JetPack导航组件的附加组件,可让您navigateUp
与捆绑包一起使用。
我还在媒体上写了blog post。
答案 6 :(得分:0)
我创建了一个类似于 LeHaine 的答案的包装函数,但它可以处理更多情况。
要将结果从子级传递给父级:
findNavController().finishWithResult(PickIntervalResult.WEEKLY)
从父级中的子级获取结果:
findNavController().handleResult<PickIntervalResult>(
viewLifecycleOwner,
R.id.navigation_notifications, // current destination
R.id.pickNotificationIntervalFragment // child destination
) { result ->
binding.textNotifications.text = result.toString()
}
我的包装器不像 LeHaine 的包装器那么简单,但它是通用的,可以处理以下情况:
Parcelable
的类查看 github 上的实现或查看 an article that explains how it works。
答案 7 :(得分:-1)
只是其他答案的替代...
以 MutableShareFlow 为核心的 EventBus 以共享对象(例如:repo)为核心,并在 here 中描述了一个观察者
看起来事情正在从 LiveData 转向 Flow 方向。
值得一看。