简体   繁体   中英

MVVM return value from Model to Repository

I Am using MVVM architecture to simple project. Then i stack in this case, when i have to return value from Model DataSource (Lambda function) to Repository then ViewModel will observe this repository. Please correct me if this not ideally and give me some advise for the true MVVM in android. i want to use LiveData only instead of RxJava in this case, because many sample in Github using RxJava. In my Model i have class UserDaoImpl, code snippet like below

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

}

And this is my Repository snippet code

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>

    }
}

Then this is my 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
    }
}

If i execute the snippet code above, the result always nullpointer in signUpResult

This is my Activity

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)
                    }
        }

Crash occured when i press register button

I'm not 100% sure, but I think the problem is in your ViewModel, where you are trying to pass by reference MutableLiveData. Your Activity is observing signUpResult MutableLiveData, but you are never posting new value, you are trying to change reference of that LiveData to one in Repository.

    val signUpResult = MutableLiveData<AppResponse>()

    fun registerUser(user: User){

        println(user.toString())

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

I think that the solution here is to let your ViewModel return LiveData, which is returned from Repository.

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

    println(user.toString())

    return registerRepository.registerUser(user)
}

And you need to observe function registerUser(user) in your Activity.

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

But now you encountered another problem. By this example you will trigger observe method every time your button is clicked. So you need to split in repository your function, you need to make one only for returning userDao.getResultCreateUser() as LiveData<AppResponse> , and the other to trigger userDao.create(user) . So you can make two functions in your repository

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

Now also in ViewModel you need to make separate function for observing result and for sending request for registration.

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

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

And finally you can observe in your function initializeUI

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

And send registration request on button click

viewModel.registerUser(user)

Sorry for long response, but I tried to explain why you need to change your approach. I hope I helped you a bit to understand how LiveData works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM