(Kotlin) Связь между фрагментами в MVVM - PullRequest
0 голосов
/ 01 апреля 2020

Я пытаюсь понять концепции MVVM, но мне трудно понять, как общаться между классом модели и пользовательским интерфейсом (фрагмент) в этом случае.

Вот (дерьмовый, имейте в виду) код:

LoginFragment.kt

class LoginFragment: Fragment(), AuthListener {

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val binding = DataBindingUtil.inflate<CredentialsLoginFragmentBinding>(
        inflater,
        R.layout.credentials_login_fragment,
        container,
        false
    )
    val viewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)
    val view: View = binding.root
    val registerButton: Button = view.findViewById(R.id.register_button)
    binding.viewModel = viewModel
    viewModel.authListener = this

    registerButton.setOnClickListener {
        val transaction: FragmentTransaction? = fragmentManager?.beginTransaction()
        transaction?.replace(R.id.fragment_container, SignupFragment())?.commit()
    }
    return view
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val constraintRoot: MotionLayout = view.findViewById(R.id.sign_in_root)
    ActivityUtils().switchLayoutAnimationKeyboard(constraintRoot = constraintRoot)

}

override fun onStarted() {
    Toast.makeText(context, "Started", Toast.LENGTH_SHORT).show()
}

override fun onSuccess() {
    Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show()
}

override fun onError(message: String) {
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}}

LoginViewModel.kt

class LoginViewModel: ViewModel(){
var username: String? = null
var password: String? = null
var isCredentialsValid: Boolean = false
var authListener: AuthListener? = null
private val context: Context? = null

fun onLoginButtonClicked(view: View){

    if(username.isNullOrEmpty() || password.isNullOrEmpty()){
        authListener?.onError("Invalid username or password")
        isCredentialsValid = false
        return
    }

    if(!username.isNullOrEmpty() && password!!.length >= 8){
        isCredentialsValid = true
        authListener?.onSuccess()
    }else{
        authListener?.onError("Invalid")
    }
}}

Теперь предположим, что я ввел имя пользователя и пароль, и оба соответствуют критериям. Теперь я хотел бы, чтобы, когда я нажимал на кнопку «Войти», текущий фрагмент, например, заменялся фрагментом меню.

Как мне достичь чего-то подобного? Я пытался заменить из класса ViewModel, но это не работает. Должен ли я взять результат «isCredentialsValid» из класса VM и ответить соответствующим образом в классе LoginFragment?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 01 апреля 2020

Вы должны использовать оперативные данные для обновления данных из viewModel для просмотра. Я опубликую код так, как это должно быть, но убедитесь, что вам необходимо понять концепцию LiveData.

LoginViewModel.kt

class LoginViewModel: ViewModel(){
var username: String? = null
var password: String? = null
var isCredentialsValid: Boolean = false
var authListener: AuthListener? = null
private val context: Context? = null
// LiveData to udpate the UI
private val _isValidCredential = MutableLiveData<Boolean>()
val isValidCredential: LiveData<Boolean> = _isValidCredential


fun onLoginButtonClicked(view: View){

if(username.isNullOrEmpty() || password.isNullOrEmpty()){
    authListener?.onError("Invalid username or password")
    isCredentialsValid = false
    return
}

if(!username.isNullOrEmpty() && password!!.length >= 8){
    isCredentialsValid = true
// to update the value of live data wherever you need
    _isValidCredential.value = true
    authListener?.onSuccess()
}else{
    authListener?.onError("Invalid")
// to update the value of live data wherever you need
    _isValidCredential.value = false
}
}
}

Ваш фрагмент должен быть

LoginFragment.kt

class LoginFragment: Fragment(), AuthListener {

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<CredentialsLoginFragmentBinding>(
    inflater,
    R.layout.credentials_login_fragment,
    container,
    false
)
val viewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)
val view: View = binding.root
val registerButton: Button = view.findViewById(R.id.register_button)
binding.viewModel = viewModel
viewModel.authListener = this

// This is the way you need to observe the value
viewModel.isValidCredential.observe(viewLifecycleOwner, Observer {

if(it){
// do your navigation stuff here
}else{
// do your stuff if not valid credential
}

    })

registerButton.setOnClickListener {
    val transaction: FragmentTransaction? = 
fragmentManager?.beginTransaction()
    transaction?.replace(R.id.fragment_container, SignupFragment())?.commit()
}
return view
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val constraintRoot: MotionLayout = view.findViewById(R.id.sign_in_root)
ActivityUtils().switchLayoutAnimationKeyboard(constraintRoot = constraintRoot)

}

override fun onStarted() {
Toast.makeText(context, "Started", Toast.LENGTH_SHORT).show()
}

override fun onSuccess() {
Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show()
}

override fun onError(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}}
0 голосов
/ 01 апреля 2020

Типичным способом обратной связи с пользовательским интерфейсом из модели представления является использование aliveata . В вашей LoginViewModel вы должны установить свои данные для жизни true или false. Внутри вашего взгляда LoginFragment.kt у вас будет наблюдатель. Эта работа для наблюдателей заключается в том, чтобы стрелять каждый раз, когда значение жилата изменяется. Таким образом, у вас может быть логика c, которая может отображать сообщение об ошибке liveData = false или запускать фрагмент меню = true.

Вот хороший пример использования liveata для передачи данных в представление (фрагмент) этого документа: https://developer.android.com/topic/libraries/architecture/viewmodel#implement

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...