TLDR: Как я могу правильно реализовать архитектуру MVVM с LiveData?
У меня есть класс фрагмента, который наблюдает за живыми данными, выставленными viewModel:
viewModel.loginResultLiveData.observe
class LoginFragment : Fragment() {
private lateinit var binding: FragmentLoginBinding
private val viewModel by fragmentScopedViewModel { injector.loginViewModel }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentLoginBinding.inflate(inflater, container, false)
val username = binding.loginInputField.toString()
val password = binding.passwordInputField.toString()
binding.loginSignInButton.setOnClickListener { viewModel.login(
username,
password
) }
viewModel.loginResultLiveData.observe(viewLifecycleOwner){
when(it){
is LoginResult.Success -> doSmth()
}
}
return binding.root
}
}
Представление класса модели просто запрашивает сопоставленный объект liveata.
class LoginViewModel @Inject internal constructor(
private val loginUseCase: LoginUseCase
) : ViewModel() {
lateinit var loginResultLiveData: MutableLiveData<LoginResult>
fun login(username: String, password: String) {
loginResultLiveData = loginUseCase.login(username, password)
}
}
Модель использует вариант использования, чтобы отобразить результат из исходного формата, а также отобразит ошибки:
class LoginUseCase @Inject internal constructor(
private val authRepository: AuthEmailRepository
) {
var loginResultLiveData = MutableLiveData<LoginResult>()
fun login(userName: String, password: String): MutableLiveData<LoginResult> {
authRepository.login(userName, password)
.addOnCompleteListener {
if (it.isSuccessful) {
loginResultLiveData.postValue(LoginResult.Success)
} else {
loginResultLiveData.postValue(LoginResult.Fail(it.exception.toString()))
}
}
return loginResultLiveData
}
}
Проблема в том, что только после нажатия loginSignInButton
модель создает объект liveData. Но я начинаю наблюдать этот объект сразу после установки onClickListener. Также каждый раз, когда нажимается кнопка, это создает новый экземпляр viewModel.loginResultLiveData
, что не имеет смысла.
binding.loginSignInButton.setOnClickListener { viewModel.login(
username,
password
) }
viewModel.loginResultLiveData.observe(viewLifecycleOwner){
when(it){
is LoginResult.Success -> doSmth()
}
}
Как в этом случае правильно реализовать архитектуру MVVM с LiveData?
Я также мог бы переместить логи c Теперь у меня есть LoginUseCase
в ModelView и затем что-то подобное, что позволяет избежать проблемы, описанной ранее. Но тогда я не могу делегировать отображение / обработку ошибок для использования case.
class LoginViewModel @Inject internal constructor(
private val loginUseCase: LoginUseCase
) : ViewModel() {
val loginResult: MutableLiveData<LoginResult> = MutableLiveData()
fun login(username: String, password: String) = loginUseCase.login(username, password)
.addOnCompleteListener {
if (it.isSuccessful) {
loginResult.postValue(LoginResult.Success)
} else {
loginResult.postValue(LoginResult.Fail(it.exception.toString()))
}
}
}