提问人:Nexussim Lements 提问时间:5/8/2023 更新时间:5/8/2023 访问量:17
Android ViewModel 不兼容的回调和捆绑范围
Android ViewModel incompatible callback and bundle scope
问:
当用户在我的 MainActivity 中与 TextView 交互时,我调用一个,并向它传递一个可用游戏列表,以便用户可以选择一个:GamesBottomSheetDialog
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
gamesViewModel = new ViewModelProvider(this).get(GamesViewModel.class);
gamesViewModel.getSelectedGame().observe(this, new Observer<Game>() {
@Override
public void onChanged(Game game) {
//WAIT FOR THE USER TO SELECT A GAME FROM THE BOTTOM SHEET LIST
}
});
initializeGameSelectorDialog();
}
private void initializeGameSelectorDialog() {
binding.preview.tvGames.setOnClickListener(view -> {
gamesBottomSheetDialog = GamesBottomSheetDialog.newInstance();
Bundle bundle = new Bundle();
bundle.putSerializable(GAMES, getAvailableGames());
gamesBottomSheetDialog.setArguments(bundle);
gamesBottomSheetDialog.show(getSupportFragmentManager(), "ModalBottomSheet");
});
}
...
}
然后我简单地实例化一个并观察游戏,直到它们被分组(自定义逻辑)并准备好在适配器中显示:GamesBottomSheetDialog
GamesViewModel
@AndroidEntryPoint
public class GamesBottomSheetDialog extends BottomSheetDialogFragment {
private GamesAdapter gamesAdapter;
private GamesViewModel viewModel;
private BottomSheetGamesBinding binding;
public GamesBottomSheetDialog() {
//REQUIRED EMPTY CONSTRUCTOR
}
public static GamesBottomSheetDialog newInstance() {
return new GamesBottomSheetDialog();
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = BottomSheetGamesBinding.inflate(getLayoutInflater());
viewModel = new ViewModelProvider(requireActivity()).get(GamesViewModel.class);
viewModel.getGameItems().observe(getViewLifecycleOwner(), new Observer<List<GameItem>>() {
@Override
public void onChanged(List<GameItem> gameItems) {
GenericUtils.changeVisibility(View.GONE, binding.progressBar);
gamesAdapter.refreshAdapter(gameItems);
}
});
...
return binding.getRoot();
}
...
//This method is a callback listener from the adapter:
@Override
public void onGameSelected(Game game) {
gamesViewModel.setGame(game);
}
}
由于我需要在用户点击适配器内的游戏项目时提供回调,因此我需要创建一个附加到 Activity 范围的“Shared ViewModel”:MainActivity
GamesBottomSheetDialog
@HiltViewModel
public class GamesViewModel extends ViewModel {
...
@Inject
GamesViewModel(GameRepository gameRepository, SavedStateHandle savedStateHandle){
this.gameRepository = gameRepository;
GameList gameList = GenericUtils.deserialize(savedStateHandle.get(GAMES), GameList.class);
if (Objects.nonNull(gameList)) {
games = gameList.getGameList();
}
selectedGame = new MutableLiveData<>();
gameItems = new MutableLiveData<>();
gameItems.setValue(groupGames(games));
}
...
public MutableLiveData<List<GameItem>> getGameItems() {
return gameItems;
}
public MutableLiveData<Game> getSelectedGame() {
return selectedGame;
}
public void setGame(Game game) {
selectedGame.setValue(game);
}
}
但是,这里存在一个很大的不兼容问题,如果我将 ViewModel 范围设置为活动,则回调可以完美运行,但是预填充游戏列表的回调始终为 null,因为 Bundle 的范围限定为 Fragment 本身而不是 Activity。这意味着,如果我从这里更改范围:SavedStateHandle
GamesViewModel
viewModel = new ViewModelProvider(requireActivity()).get(GamesViewModel.class);
对此:
viewModel = new ViewModelProvider(this).get(GamesViewModel.class);
in ViewModel 不再是 null,但现在回调不起作用,因为 的作用域与位于 中的作用域不同。SavedStateHandle
MainActivity
GamesBottomSheetDialog
有没有办法以兼容的方式使用我的 Bundle 和回调?
答: 暂无答案
评论