我是否必须始终从 fragment/activity 调用视图模型中的方法?

do I have to always call my method in viewmodel from fragment/activity?

所以我是 Android 中 MVVM 模式的新手。单击按钮时,我想执行两个操作 然后首先我检查互联网连接,如果互联网连接可用然后执行登录到服务器。

这是我的 ViewModel

class LoginViewModel(application: Application) : AndroidViewModel(application) {


    private val _hasInternetConnection = MutableLiveData(false)
    val hasInternetConnection: LiveData<Boolean>
        get() = _hasInternetConnection


    fun checkIfItHasInternetConnection() {

        if (InternetConnection.checkConnection(getApplication())) {
            _hasInternetConnection.value = true
        } else {
            _hasInternetConnection.value = false

        }

    }

    fun performLogin() {

    }



}

这是我的片段

class LoginFragment : Fragment() {

    lateinit var model: LoginViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        model = ViewModelProvider(this).get(LoginViewModel::class.java)

        button.setOnClickListener {
            model.checkIfItHasInternetConnection()
        }

        model.hasInternetConnection.observe(this, Observer { hasInternetConnection ->

            if (!hasInternetConnection) {
                longToast("You have no internet connection")
            } else {

            }

        })



    }


}

问题是,我不确定我必须在哪里调用我的视图模型中的 performLogin 方法,我是否必须像在观察者中这样在我的片段中调用它?

model.hasInternetConnection.observe(this, Observer { hasInternetConnection ->

            if (!hasInternetConnection) {
                longToast("You have no internet connection")
            } else {
                model.performLogin()
            }

 })

或者我是否必须在执行互联网连接检查后在视图模型本身内部调用它?像这样

// inside viewModel
fun checkIfItHasInternetConnection() {

        if (InternetConnection.checkConnection(getApplication())) {
            _hasInternetConnection.value = true
            performLogin()
        } else {
            _hasInternetConnection.value = false

        }

    }

sorry 如果问题太基础了,我尝试学习MVVM,从我看的教程来看,好像我必须从片段中调用viewModel中的方法,但如果我调用它会更方便从视图模型本身。我需要知道解决这种情况的正确方法

您可以使用这两种方法,但从代码分离的角度来看,您将遵循第一种方法

我建议你看看Android Developer Guide to App Architecture。它基于 MVVM 架构,并引入了一个处理网络调用的存储库。也许这会对你有所帮助。

但要回答你的问题:遵循清晰的 MVVM 架构,Activity 应该只调用 ViewModel 中的方法,而不执行任何逻辑。然后 ViewModel 中的这个方法应该执行逻辑,或者进一步向下委托给模型,或者,例如,一个存储库。

如果由于缺少互联网连接而无法执行登录,ViewModel 应该通过设置一些 LiveData 来处理这个问题,也许 LiveData<String> errorMessage,并且 Activity 应该观察这个 LiveData 并显示一条消息每当此 LiveData 提供新字符串时,都会向用户提供。

编辑:一些示例代码。

存储库:

public void performLogin(String username, String password, MutableLiveData<LoginStatus> loginStatus) {
  if (/*check Internet access*/) {
    performLoginAsync(username, password, loginStatus);
  } else {
    loginStatus.setValue(LoginStatus.NO_INTERNET);
  }
}
private void performLoginAsync(String username, String password, MutableLiveData<LoginStatus> loginStatus) {
  /*perform async login with success and error callback*/
  myWebservice.login(
    username,
    password,
    () -> loginStatus.setValue(LoginStatus.SUCCESS), /*success callback*/
    error -> loginStatus.setValue(LoginStatus.ERROR) /*error callback*/
  );
}

视图模型:

public MutableLiveData<LoginStatus> loginStatus;
private Repository myRepository;
public void performLogin(String username, String password) {
  myRepository.performLogin(username, password, loginStatus);
}

片段:

private ViewModel myViewModel;
private EditText loginUsername, loginPassword;
private Button loginButton;

/* in some method, where you want your initialization, e.g. in onViewCreated */
  loginButton.setOnClickListener(v -> {
    myViewModel.login(loginUsername.getText().toString(), loginPassword.getText().toString());
  });
  myViewModel.loginStatus.observe(this, loginStatus -> Toast.makeText(this, loginStatus.getText(), Toast.LENGTH_LONG));

此代码不是一个工作示例,但它应该包含其中的大部分内容并且应该为您指明正确的方向。希望能帮助到你。如果有什么不清楚的地方,再发表评论