【发布时间】:2020-04-03 20:48:12
【问题描述】:
考虑以下场景。我有两个片段,FormFragment 和 SelectionFragment 由 MainActivity 托管。我有一个SharedViewModel,我计划将其用于片段之间的数据通信。
FormFragment 有一个微调器,点击它会打开SelectionFragment。
SelectionFragment 包含一个 RecyclerView,其中包含一个 Item 对象列表。
SharedViewModel 有两个 LiveData,LiveData<Item> selectedItem 和 LiveData<List<Item>> items
用例:
- 在应用启动时,用户登陆
FormFragment,它有一个没有选定项目的微调器 - 当用户点击微调器时,我们导航到
SelectionFragment -
SelectionFragment从SharedViewModel获取项目列表并填充 RecyclerView - 当用户点击一个项目时,我们更新
SharedViewModel中的selectedItem并从后面的堆栈中弹出SelectionFragment以返回到FormFragment -
FormFragmentspinner 现在显示所选项目 - 用户可以通过执行相同的过程来选择不同的项目
问题:
在完成上面的步骤 1 到 5 之后,当我们尝试通过再次执行步骤 1 来选择另一个项目时,SelectionFragment 内部的观察者立即触发(因为selectedItem 不是null),并从回栈。这显然不是我们想要的行为,因为我们希望用户能够随意选择不同的项目。
如何正确观察SelectionFragment 内部的selectedItem,使其不会立即触发其观察者?
class FormFragment extends Fragment {
@BindView(R.id.spinner) protected Spinner spinner;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
SharedViewModel viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel.class);
viewModel.getSelectedItem().observe(getViewLifecycleOwner(), selectedItem -> {
spinner.setSelected(selectedItem);
});
spinner.setOnClickListener(v -> {
// navigate to SelectionFragment
requireFragmentManager().beginTransaction().replace(R.id.container, new SelectionFragment()).commit();
});
}
}
class SelectionFragment extends Fragment {
@BindView(R.id.recycler_view) protected RecyclerView recyclerView;
private ItemsAdapter adapter = new ItemsAdapter();
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
SharedViewModel viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel.class);
viewModel.getItems().observe(getViewLifecycleOwner(), items -> {
// load items into recycler view
adapter.submitList(new ArrayList<>(items));
});
viewModel.getSelectedItem().observe(getViewLifecycleOwner(), selectedItem -> {
// pop fragment from back stack
requireFragmentManager().popBackStackImmediate();
});
adapter.setOnItemClickedListener(item -> {
// update selected item in view model when user taps on an item in the list
viewModel.setSelectedItem(item);
});
recyclerView.setAdapter(adapter);
}
}
class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selectedItem = new MutableLiveData<>();
private Repository repository;
// repository is injected (unimportant to the problem)
SharedViewModel(Repository repository) {
this.repository = repository;
}
LiveData<List<Item>> getItems() {
return repository.getItems();
}
LiveData<Item> getSelectedItem() {
return selectedItem;
}
void setSelectedItem(Item item) {
selectedItem.setValue(item);
}
}
【问题讨论】:
标签: android android-fragments mvvm android-livedata android-viewmodel