简体   繁体   中英

How to Return LiveData from Repository

I just can't see how to chain LiveData from Repo to VM, so I have tried to boil this down to the most simple of example!:

Fragment

class LoginFragment : Fragment() {

private lateinit var loginViewModel: LoginViewModel
private var mCurrentName = "Blank!"

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    // Inflate the layout for this fragment
    val binding: LoginFragmentBinding = DataBindingUtil.inflate(
        inflater, R.layout.login_fragment, container, false)

    binding.apply {
        loginButton.setOnClickListener{
            loginViewModel.changeText()
        }
    }
    return binding.root
}


override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    loginViewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)

    loginViewModel.getCurrentName().observe(viewLifecycleOwner, Observer {
        mCurrentName = it      // I'm expecting mCurrentName to equal "Button Clicked!" when button clicked..
        makeToast()     // Toast works, but variable remains unchanged..
    })

}

private fun makeToast() {
    Toast.makeText(activity, mCurrentName, Toast.LENGTH_LONG).show()
}

ViewModel

class LoginViewModel : ViewModel() {

private val firestoreRepository : FirestoreRepository = FirestoreRepository()
private var mCurrentName = MutableLiveData<String>()

fun changeText(){
    mCurrentName = firestoreRepository.changeText()
}

Repository

class FirestoreRepository {

    private val mCurrentName = MutableLiveData<String>()

    fun changeText(): MutableLiveData<String> {
            mCurrentName.value = "Button Clicked!!"
            return mCurrentName
    }

I'm assuming I have misunderstood how the observer function works..

Actually If you are maintaining LiveData in repository, I don't think there's a need of separate LiveData in ViewModel as well. You just have to observe the LiveData once from the activity. Then make any changes to repository instance directly. So If I have to show it in your code, It might look something like this.

  1. Activity class: Change makeToast method to observeCurrentName() like this:

     private fun observeCurrentName() { vm.getCurrentName().observe(this, Observer{ //Toast here }) }
  2. Your VM:

     class LoginViewModel : ViewModel() { ... fun getCurrentName(): MutableLiveData<String>{ return repository.getCurrentName() } fun setCurrentName(name: String?){ repository.setCurrentName(name) } ... }
  3. Your repository:

     class FirestoreRepository { private val mCurrentName = MutableLiveData<String>() fun getCurrentName(): MutableLiveData<String>{ return mCurrentName } fun setCurrentName(name: String?){ mCurrentName.value = name //This will trigger observer in Activity } }

No need to change MutableLiveData inside ViewModel . Try to pass whatever Repository send to View . Check below

class LoginViewModel : ViewModel() {

    private val firestoreRepository : FirestoreRepository = FirestoreRepository()

    fun getCurrentName(): MutableLiveData<String> {
        return firestoreRepository.getCurrentName()
    }

    fun changeText() {
        firestoreRepository.changeText()
    }
}

And also your FirestoreRepository

class FirestoreRepository {

    private val mCurrentName = MutableLiveData<String>()

    fun getCurrentName(): MutableLiveData<String> {
        return mCurrentName
    }

    fun changeText() {
        mCurrentName.value = "Button Clicked!!"
    }
}

You're changing mCurrentName (the LiveData variable itself as opposed to it's contents) after you start observing it. The guidance seems to be to not use LiveData in Repository layer (use Coroutines/Flow instead for example)....but for now you could have something like following (or perhaps use one of the LiveData Transformations)

private val mCurrentName = firestoreRepository.currentName()

fun changeText(){
    firestoreRepository.changeText()
}

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