使用 ViewModel 仅在用户干预时调用

Using ViewModel to only invoke on user intervention

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

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

我的(诚然很差)viewmodel 是:

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);
}

我考虑过何时进行观察,但不确定如何最好地处理此数据保留问题

我现在唯一能想到的方法就是将一个布尔值应用于 isUserClicked 的 submitDetails,然后在 onCreateView 中将其设置为 false,然后在 submitDetails 中再次将其设置为 true,然后将观察者更改为 && 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();
            }