【问题标题】:MVVM return value from Model to Repository从模型到存储库的 MVVM 返回值
【发布时间】:2019-07-20 09:59:54
【问题描述】:

我正在使用 MVVM 架构来进行简单的项目。然后我在这种情况下堆叠,当我必须从模型数据源(Lambda 函数)返回值到存储库时,ViewModel 将观察这个存储库。如果这不理想,请纠正我,并给我一些关于 android 中真正的 MVVM 的建议。在这种情况下,我只想使用 LiveData 而不是 RxJava,因为 Github 中的许多示例都使用 RxJava。 在我的模型中,我有类 UserDaoImpl,代码 sn-p 如下所示

class UserDaoImpl : UserDao {

    private val resultCreateUser = MutableLiveData<AppResponse>()


    private val mAuth : FirebaseAuth by lazy {
        FirebaseAuth.getInstance()
    }

    override fun createUser(user: User) {

        mAuth.createUserWithEmailAndPassword(user.email, user.password)
            .addOnCompleteListener {

            //I DID NOT REACH THIS LINE

                println("hasilnya ${it.isSuccessful} ")

                if(it.isSuccessful){
                    val appResponse = AppResponse(true, "oke")
                    resultCreateUser.postValue(appResponse)
                }else{
                    val appResponse = AppResponse(false, "not oke -> ${it.result.toString()}")
                    resultCreateUser.postValue(appResponse)
                }
            }
            .addOnFailureListener {

                println("hasilnya ${it.message}")

                val appResponse = AppResponse(false, "not oke -> ${it.message}")
                resultCreateUser.postValue(appResponse)
            }
    }
    override fun getResultCreateUser() = resultCreateUser

}

这是我的存储库 sn-p 代码

class RegisterRepositoryImpl private constructor(private val userDao: UserDao) : RegisterRepository{

    companion object{
        @Volatile private var instance : RegisterRepositoryImpl? = null

        fun getInstance(userDao: UserDao) = instance ?: synchronized(this){
            instance ?: RegisterRepositoryImpl(userDao).also {
                instance = it
            }
        }

    }
    override fun registerUser(user: User) : LiveData<AppResponse> {

        userDao.createUser(user)
        return userDao.getResultCreateUser() as LiveData<AppResponse>

    }
}

那么这是我的 ViewModel

class RegisterViewModel (private val registerRepository: RegisterRepository) : ViewModel() {
    val signUpResult = MutableLiveData<AppResponse>()

    fun registerUser(user: User){

        println(user.toString())

        val response = registerRepository.registerUser(user)
        signUpResult.value = response.value
    }
}

如果我执行上面的sn-p代码,结果总是signUpResult中的空指针

这是我的活动

lateinit var viewModel: RegisterViewModel
override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_register)
            initializeUI()

        }

    private fun initializeUI() {
            val factory = InjectorUtils.provideRegisterViewModelFactory()
            viewModel = ViewModelProviders.of(this, factory).get(RegisterViewModel::class.java)
            viewModel.signUpResult.observe(this, Observer {

                //IT always null
                if(it.success){
                    // to HomeActivity
                    Toast.makeText(this, "Success! ${it.msg}", Toast.LENGTH_SHORT).show()
                }else{
                    Toast.makeText(this, "FALSE! ${it.msg}", Toast.LENGTH_SHORT).show()

                }
            })

            register_btn.setOnClickListener {
                        val username = name.text.toString()
                        val email = email.text.toString()
                        val password = password.text.toString()
                        val phone = number.text.toString()
                        val user = User(0, username,"disana", email, password, "disana")
                        viewModel.registerUser(user)
                    }
        }

当我按下注册按钮时发生崩溃

【问题讨论】:

  • 您好,请问您的具体问题是什么?
  • 我不知道如何从 firebase-auth 获取值,然后将值传递给 RegisterRepositoryImpl。

标签: android kotlin mvvm firebase-authentication android-livedata


【解决方案1】:

我不是 100% 确定,但我认为问题出在您的 ViewModel 中,您试图通过引用 MutableLiveData 传递。您的 Activity 正在观察 signUpResult MutableLiveData,但您从未发布新值,您正在尝试将 LiveData 的引用更改为 Repository 中的一个。

    val signUpResult = MutableLiveData<AppResponse>()

    fun registerUser(user: User){

        println(user.toString())

        val response = registerRepository.registerUser(user)
        signUpResult.value = response.value
    }

我认为这里的解决方案是让你的ViewModel返回LiveData,它是从Repository返回的。

fun registerUser(user: User): MutableLiveData<AppResponse> {

    println(user.toString())

    return registerRepository.registerUser(user)
}

并且你需要在你的 Activity 中观察函数 registerUser(user)。

viewModel.registerUser(user).observe(this, Observer {

但是现在你遇到了另一个问题。通过这个例子,你将在每次点击按钮时触发观察方法。因此,您需要在存储库中拆分您的函数,您只需创建一个用于返回userDao.getResultCreateUser() as LiveData&lt;AppResponse&gt;,另一个用于触发userDao.create(user)。 所以你可以在你的存储库中创建两个函数

override fun observeRegistrationResponse() : LiveData<AppResponse> {
    return userDao.getResultCreateUser() as LiveData<AppResponse>
}
override fun registerUser(user: User) {
    userDao.createUser(user)
}

现在在 ViewModel 中,您还需要创建单独的函数来观察结果和发送注册请求。

fun observeRegistrationResponse(): LiveData<AppResponse> {
    return registerRepository.observeRegistrationResponse()
}

fun registerUser(user: User){
    println(user.toString())
    registerRepository.registerUser(user)
}

最后你可以在你的函数 initializeUI 中观察

viewModel.observeRegistrationResponse().observe(this, Observer {

点击按钮发送注册请求

viewModel.registerUser(user)

抱歉,回复太长了,但我试图解释为什么你需要改变你的方法。希望对您了解 LiveData 的工作原理有所帮助。

【讨论】:

  • 很好的答案。我知道了谢谢。所以结论是我必须创建单独的函数来触发输入动作和接收视图模型中的动作?
  • 是的,你是对的。无需对同一个 LiveData 调用多次观察函数。
猜你喜欢
  • 1970-01-01
  • 2020-12-08
  • 2014-03-10
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 2023-03-09
  • 1970-01-01
相关资源
最近更新 更多