2 回答

TA貢獻1802條經驗 獲得超5個贊
我在 android 中看到過很多MVVM
模式的實現。我在我的項目中遵循以下結構。我不知道這是否理想。如果錯了請糾正我。
首先讓我回答你的問題,
在哪里驗證 MVVM 中的登錄表單?
我在中進行驗證ViewModel
class LogInViewModel : ViewModel() {
? ? ...
? ? fun performValidation() {
? ? ? ? if (username.isBlank()) {
? ? ? ? ? ? logInResult.value = "Invalid username"
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? if (password.isBlank()) {
? ? ? ? ? ? logInResult.value = "Invalid password"
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? logInResult.value = "Valid credentials :)"
? ? }
}
意識形態上正確的解決方案是什么?
正如我所說,我們可以遵循許多結構在 android 中實現 MVVM。下面給出了我如何做的例子。代碼中充滿了注釋,所以我相信它是可以自我理解的。無論如何,請隨時在評論中要求任何澄清。(為了可讀性,我從布局文件中刪除了一些代碼)
登錄視圖模型
class LogInViewModel : ViewModel() {
? ? /**
? ? ?* Two way bind-able fields
? ? ?*/
? ? var username: String = ""
? ? var password: String = ""
? ? /**
? ? ?* To pass login result to activity
? ? ?*/
? ? private val logInResult = MutableLiveData<String>()
? ? fun getLogInResult(): LiveData<String> = logInResult
? ? /**
? ? ?* Called from activity on login button click
? ? ?*/
? ? fun performValidation() {
? ? ? ? if (username.isBlank()) {
? ? ? ? ? ? logInResult.value = "Invalid username"
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? if (password.isBlank()) {
? ? ? ? ? ? logInResult.value = "Invalid password"
? ? ? ? ? ? return
? ? ? ? }
? ? ? ? logInResult.value = "Valid credentials :)"
? ? }
}
登錄處理器
/**
?* To pass UI events to activity
?*/
interface LogInHandler {
? ? /**
? ? ?* Will be called when login button gets clicked
? ? ?*/
? ? fun onLogInClicked()
}
activity_login.xml
<layout>
? ? <data>
? ? ? ? <variable
? ? ? ? ? ? name="viewModel"
? ? ? ? ? ? type="com.theapache64.mvvmloginsample.LogInViewModel" />
? ? ? ? <variable
? ? ? ? ? ? name="handler"
? ? ? ? ? ? type="com.theapache64.mvvmloginsample.LogInHandler" />
? ? </data>
? ? <androidx.constraintlayout.widget.ConstraintLayout>
? ? ? ? <EditText
? ? ? ? ? ? ...
? ? ? ? ? ? android:text="@={viewModel.username}" <!--Two way binding username-->
? ? ? ? />
? ? ? ? <EditText
? ? ? ? ? ? ...
? ? ? ? ? ? android:text="@={viewModel.password}" <!--Two way binding password-->
? ? ? ? />
? ? ? ? <Button
? ? ? ? ? ? ...
? ? ? ? ? ? android:onClick="@{()->handler.onLogInClicked()}" <!--Invoked on button click-->
? ? ? ? />
? ? </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
最后是活動
登錄活動
class LogInActivity : AppCompatActivity(), LogInHandler {
? ? private lateinit var viewModel: LogInViewModel
? ? override fun onCreate(savedInstanceState: Bundle?) {
? ? ? ? super.onCreate(savedInstanceState)
? ? ? ? // Binding
? ? ? ? val binding =
? ? ? ? ? ? DataBindingUtil.setContentView<ActivityLoginBinding>(this, R.layout.activity_login)
? ? ? ? // ViewModel
? ? ? ? this.viewModel = ViewModelProviders.of(this).get(LogInViewModel::class.java)
? ? ? ? // Setting binding params
? ? ? ? binding.viewModel = viewModel
? ? ? ? binding.handler = this
? ? ? ? // Watching for login result
? ? ? ? viewModel.getLogInResult().observe(this, Observer { result ->
? ? ? ? ? ? Toast.makeText(this, result, Toast.LENGTH_SHORT).show()
? ? ? ? })
? ? }
? ? override fun onLogInClicked() {
? ? ? ? viewModel.performValidation()
? ? }
}
我在 GitHub 中托管了完整的源代碼。

TA貢獻1797條經驗 獲得超6個贊
首先,您應該使用雙向數據綁定并將文本值分配給視圖模型中的可觀察字段并使用這樣的函數
private fun validateFields(): Boolean {
if (email.value.isNullOrBlank()) {
return false
}
if (password.value.isNullOrBlank()) {
return false
}
return true
}
要驗證您的字段,您可以根據需要添加更多級別的驗證。
然后您可以將以下功能附加到布局中的登錄按鈕
fun loginUser() {
if (validateFields()) {
val job = viewModelScope.launch(Dispatchers.IO) {
result.postValue(
repo.makeLoginRequest(
email = email.value,
password = password.value
)
)
}
}
}
并隨心所欲地使用結果,這里我使用的是實時數據和協程
檢查電子郵件是否有效使用:
private fun isValidEmail(): Boolean = android.util.Patterns.EMAIL_ADDRESS.matcher(email.value).matches()
添加回答
舉報