在使用MVVM模式时,业务逻辑应该放在哪里?

12
我正在使用MVVM设计模式制作用户登录界面,但在实现电话号码验证的逻辑时遇到了困难。我阅读了在使用MVVM时需要遵循的规则(第4条规则),即视图不应该有任何逻辑,甚至没有简单的if条件语句。所有与视图相关的逻辑都发生在ViewModel中。
以下是我的ViewModel类。
public class LoginViewModel extends AndroidViewModel {

    private LoginRepository loginRepository;
    private HashMap<String,String> mNumberParam;
    private MutableLiveData<Boolean> isValidated;

    public LoginViewModel(@NonNull Application application) {
        super(application);
        loginRepository=LoginRepository.getInstance();
        isValidated=new MutableLiveData<>();
    }


    public LiveData<List<OtpEnterModel.Data>> enterNumberApiHit(){
        return loginRepository.enterNumberApiHit(mNumberParam);
    }


    public void onSubmitClick(String number){

        //if mobile number not enter or wrong enter show message ,and tell the view to hide other view
        if (number==null) {
            Toast.makeText(getApplication(), "Invalid mobile number", Toast.LENGTH_SHORT).show();
            isValidated.setValue(false);

        } else {
            //otherwise save mobile number in hashMap ,and tell the view to work further
            isValidated.setValue(true);
            saveNumberParam(number);
        }
    }

    //to save the mobile number in hashMap with key i.e mobile_number.
    private void saveNumberParam(String mobileNumber) {

        //if hashMap null then initialize it
        if (mNumberParam ==null) {
            mNumberParam = new HashMap<>();
        }
        mNumberParam.put(MyConstant.MOBILE_NUMBER, mobileNumber);
    }

    public LiveData<Boolean> isValidated(){
      return isValidated;
    }
}

这是我的View类。

public class EnterNumber extends AppCompatActivity implements View.OnClickListener, FragmentManager.OnBackStackChangedListener {

    //dataType
    private Context context;
    private FragmentManager manager;
    private LoginViewModel loginViewModel;

    //views
    private EditText enterMobileEDT;
    private ProgressBar progressBar;
    private Button btnNumber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_enter_number);

        manager=getSupportFragmentManager();
        context = EnterNumber.this;
        loginViewModel= ViewModelProviders.of(this).get(LoginViewModel.class);

        init();
        setListener();
    }

    //all views initialize here
    private void init() {
        enterMobileEDT = findViewById(R.id.enterMobileET);
        progressBar=findViewById(R.id.progressBar);
        btnNumber=findViewById(R.id.btn_number);
    }

    //listener for views
    private void setListener() {
        btnNumber.setOnClickListener(this);
        manager.addOnBackStackChangedListener(this);
    }

    //check for mobile number and send otp by hitting API
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_number) {
            loginViewModel.onSubmitClick(enterMobileEDT.getText().toString());
            numberValidation();
        }
    }

    //check for editText length
    public void numberValidation() {

        loginViewModel.isValidated().observe(this, new Observer<Boolean>() {
            @Override
            public void onChanged(Boolean aBoolean) {

                if(aBoolean){
                    loginApiHit();
                }
                hideShowView(aBoolean);
            }
        });
    }

    //hide and show the view based on condition
    public void hideShowView(boolean wantToShowProgress) {

        if(!wantToShowProgress){
            progressBar.setVisibility(View.INVISIBLE);
            btnNumber.setEnabled(true);

        }else {
            progressBar.setVisibility(View.VISIBLE);
            btnNumber.setEnabled(false);
        }
    }

}

如何将所有if/else条件从View移动到ViewModel中?


无论是Java还是Kotlin或其他语言,你的业务逻辑是什么?你能简单地总结一下你的业务逻辑吗? - Phan Sinh
简单来说,它可以是电子邮件和密码验证。 - Lokik Soni
业务逻辑应该包含在数据层(例如模型类)中。 - Ethan Choi
@EthanChoi,那我应该将邮件和密码编辑文本字符串传递到模型中进行验证吗? - Lokik Soni
我猜如果你想完全删除逻辑,你可以将if条件移到viewModel中,并观察View.Visibility和按钮状态。但是你的逻辑也很好。这里有一篇关于这个主题的文章: https://www.freecodecamp.org/news/model-view-viewmodel-android-tutorial/ - moonLander_
1个回答

7

问题

如何将所有if / else条件从View移动到ViewModel中?

  • 建议您在 View 中删除所有业务逻辑
  • View仅具有更新UI的代码,该代码耦合了 ViewModel 数据(LiveData),可以通过 ViewDataBininding 库减少。
  • 最后,View只有与设置 ViewDataBinding ViewModel 相关的代码。

ViewModel

public class LoginViewModel extends AndroidViewModel {
    ...
    private MutableLiveData<String> _email = new MutableLiveData<>(); // is binded some UI such as EditText..

    LiveData<Boolean> emailValidate = Transformations.map(_email, this::emailValidate);

    private boolean emailValidate(String email) {
        return true; // implements email validation logic
    }
    ...
}

视图

...
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
    super.onCreate(savedInstanceState, persistentState);
    LoginViewModel loginViewModel= ViewModelProviders.of(this).get(LoginViewModel.class);
    subscribe(loginViewModel);
}

private void subscribe(LoginViewModel loginViewModel) {
    loginViewModel.emailValidate.observe(this, this::setEmailValidateLayout); 
    // You shouldn't implement observing in the onClick event. Overlapping observers problem.
}

private void setEmailValidateLayout(boolean validate) {
    progressBar.setVisibility(validate ? View.VISIBLE : View.INVISIBLE);
    btnNumber.setEnabled(validate);
}
...

但是在你的答案中,还有if/else条件,所以它与我的代码有何不同? - Lokik Soni
@LokikSoni,怎么了?你代码中的if/else条件没有问题。请注意,我已经根据你的情况修改了代码。 - Ethan Choi
电子邮件验证不应直接在ViewModel中实现,而应该委托给封装这些业务规则的领域/模型层实现。 - Carter Hudson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接