Search code examples
androidkotlinandroid-livedataandroid-architecture-componentsandroid-viewmodel

can I make a livedata observer in my viewmodel? or should I always observer in fragment/activity?


I am new to MVVM. so I have 2 requests to the server from my fragment/activity, the result from the first request will be used as an input parameter for the second request.

so first in my fragment, when a button is clicked then I make a request to check whether the user is banned or not, if not then this user can create a post.

so first I check if a user is banned or not using this code in my fragment

class CreateEventFragment : Fragment() {

    lateinit var model: CreateEventViewModel


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        model = ViewModelProvider(this).get(CreateEventViewModel::class.java)

        button.setOnClickListener {
            model.checkIfUserIsBanned()
        }

    }


}

and here is the viewmodel

class CreateEventViewModel(application: Application) : AndroidViewModel(application) {

    val mUserIsBanned :MutableLiveData<Boolean> = UserClient.mUserIsBanned

    fun checkIfUserIsBanned(userID: String) {
        UserRepository.checkIfUserIsBanned(id)
    }


}

and here is the client ( I skip the repository for simplicity)

object UserClient {

    val mUserIsBanned = MutableLiveData<Boolean>()

    fun checkIfUserIsBanned(userID: String) {

        // perform networking, after getting the value then

        if (user.isBanned) {
            mUserIsBanned.postValue(true)
        } else {
            mUserIsBanned.postValue(false)
        }

    }



}

here is the problem, the second request needs the result of the first result, i.e the mUserIsBanned is need to check if the user is not banned then perform the second request (user create a post). my question is, where do I place this logic ? in viewmodel or in my fragment?

if (userIsBanned == false) {
   createPost()
}

from the tutorial I have seen, it seems the livedata is always observed in a fragment. so the first option is to place the logic in fragment like this

    model.mUserIsBanned.observe(viewLifecycleOwner, Observer { isBanned ->

        val userIsBanned = isBanned ?: return@Observer

        if (!userIsBanned) {
            model.createPost()
        }

    })

is it okay to place code checking like that in a fragment?

actually I don't need to observed the isBanned, I just need to check it once

or the second option is to check userIsBanned or not in viewmodel, but I don't know how to do livedata observation in viewmodel

or my approach is all wrong ? I am not sure using this MVVM

please help, java is also ok.


Solution

  • You can try MediatorLiveData for your second operation. What MediatorLiveData does is, it creates a listenable container for your various LiveData objects & provide you callback once any of the underlying/observing value changes.

    Example: Assume that LiveData<B> needs to be called on any value changes from LiveData<A>, here you can consider LiveData<B> as MediatorLiveData.

    So declaration for LiveData<B> would be:

    val bLiveData : LiveData<B> = MediatorLiveData<B>().apply {
        addSource(aLiveData) { aData ->
            value = convertADataToB(aData) //value is backing property for getValue()/setValue() method, use postValue() explicitly upon bg operation
        }
    }
    

    In your case, put this code inside your ViewModel:

    val createPostLiveData: LiveData<Boolean> = MediatorLiveData<Boolean>().apply {
        addSource(mUserIsBanned) { flag ->
            if (!flag) {
                createPost() // Check whether you can return result from here and provide to this mediator livedata a value
            }
        }
    }
    

    Refer MediatorLiveData