首页 > 解决方案 > 使用 ViewModel 仅在用户干预时调用

问题描述

在我的片段中,检查用户以查看他们的电子邮件是否在数据库中并转到注册或登录流程,我使用 ViewModel,此视图模型使用电子邮件作为 MutableLiveData,这工作正常,但是当用户返回时,它会记住电子邮件已经保存,然后立即与 API 对话,再次将它们向前推。

等待用户调用的方法是什么?到目前为止,对于其他所有内容,使用菜单,它会在没有用户干预的情况下获取数据并在更改时更改显示给用户的数据是正确的。然而这是不同的。

我的(当然很差)视图模型是:

public class ExistingUserViewModel extends ViewModel {
    private final MutableLiveData<String> email = new MutableLiveData<>();
    private final LiveData<ApiResponse<ExistingUserResponse>> existingUser;

    @Inject
    public ExistingUserViewModel(@NonNull ExistingUserRepository existingUserRepository){
        existingUser = Transformations.switchMap(email, input -> {
            if (input == null){
                return AbsentLiveData.create();
            }
            return existingUserRepository.isExistingUser(input);
        });
    }

    public LiveData<ApiResponse<ExistingUserResponse>> getIsExistingUser() { return existingUser; }

    @VisibleForTesting
    public void setEmail(String email1){
        email.setValue(email1);
    }
}

我的片段:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    ((MainActivity) getActivity()).getSupportActionBar().hide();
    existingUserViewModel = ViewModelProviders.of(this, viewModelFactory).get(ExistingUserViewModel.class);
    existingUserListener();
}

private void refreshAndObserve() {
    existingUserViewModel.getIsExistingUser().observe(this, result -> {
        if (result.isSuccessful()) {
            try {
                String email = binding.get().emailEditText.getText().toString();
                if (result.body.getExists()) { // user exists
                    navigationController.navigateToLogin(email,null);
                } else {
                    navigationController.navigateToRegisterName(email);
                }
            } catch (NullPointerException e){
                Toast.makeText(getActivity(),e.toString(),Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(getActivity(),result.errorMessage,Toast.LENGTH_SHORT).show();
        }
    });
}

private void existingUserListener(){
    binding.get().continueButton.setOnClickListener(v -> submitDetails(v));
    binding.get().emailEditText.setOnKeyListener((v, keyCode, event) -> {
        if ((event.getAction() == KeyEvent.ACTION_DOWN)
                && (keyCode == KeyEvent.KEYCODE_ENTER)) {
            submitDetails(v);
            return true;
        }
        return false;
    });
}

private void submitDetails(View v) {
    refreshAndObserve();
    String email = binding.get().emailEditText.getText().toString();
    dismissKeyboard(v.getWindowToken());
    //todo: if valid do below
    existingUserViewModel.setEmail(email);
}

我玩过什么时候进行观察,但不确定如何最好地处理这个数据保留问题

标签: javaandroidmvvmobserver-pattern

解决方案


我现在能想到的唯一方法是将一个布尔值应用于 submitDetails 到 isUserClicked 并将其设置为 false 在 onCreateView 中并再次将其设置为 true submitDetails 然后将观察者更改为 && isUserClicked。对此作为解决方案不满意,但它至少会起作用。

还注意到我必须删除一个观察者,因为它正在堆叠到我的 popstack 上,所以解决了,如果其他人有兴趣

            try {
                String email = binding.get().emailEditText.getText().toString();
                existingUserViewModel.getIsExistingUser().removeObservers(this);
                if (result.body.getExists()) { // user exists
                    navigationController.navigateToLogin(email, null);
                } else {
                    navigationController.navigateToRegisterName(email);
                }
            } catch (NullPointerException e) {
                Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_SHORT).show();
            }

推荐阅读