0

How to use a livedata as an argument for another function? Every time I get a null value, I guess the function is called before the livedata can return hence the null value. I'm not using it from a View. I'm using it from the viewmodel, the function updateFirstName is from the viewmodel. The token comes as a Flow from the Preference Store. All answers are appreciated thanks.

    var token: LiveData<String> = appPreferenceStorage.accessToken.asLiveData()

    @ExperimentalCoroutinesApi
    private val _token: MutableLiveData<String>
        get() = token as MutableLiveData<String>
    fun updateFirstName(view: View) {
        viewModelScope.launch {

            profileRepository.updateFirstName(_token.value.toString(), "Bob", object : ProfileListener {
                override fun onSuccess(response: String?) {
                    Timber.d(response)
                }

                override fun onFailure(localizedMessage: String?) {
                    Timber.e(localizedMessage)
                }

            })
        }
    }```
Dr4ke the b4dass
  • 1,184
  • 2
  • 17
  • 40

2 Answers2

1

LiveData can be observed which gives you the ability to "read" it this way:

yourModel.token.observe(viewLifecycleOwner) { token ->

    //Here do whatever you like with "token"

}

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
Fabrizio Ferrari
  • 869
  • 2
  • 12
  • 25
  • I'm not using it from a View. I'm using it from the viewmodel, the function updateFirstName is from the viewmodel. – Dr4ke the b4dass May 20 '21 at 11:36
  • 1
    Can't you move that function in the fragment and use the observer? – Fabrizio Ferrari May 20 '21 at 14:57
  • I did that, it worked, but this is not what I want. Is there a problem with my approach? – Dr4ke the b4dass May 20 '21 at 18:53
  • I don't see any problems, even though I think it is unusual to have logic in the ViewModel which is supposed to be used as a bridge between UI and Logic (please, correct me if I am wrong, I am still learning here!). The way I have learned is to set up live-data variables in the ViewModel and observe them in the fragment for action. – Fabrizio Ferrari May 20 '21 at 19:41
  • I think in MVVM the View(fragemnt, activity, xml) should be dumb, and logic should be implemented in Viewmodel. – Dr4ke the b4dass May 20 '21 at 23:46
  • I think this document explains everything very well: https://developer.android.com/topic/libraries/architecture/viewmodel – Fabrizio Ferrari May 21 '21 at 02:25
0

First, there should be no "view" references inside your viewmodel, as this would couple your viewmodel with it's given view (fragment perhaps?).

So your function updateFirstName(view:View) should be changed to updateFirstName(name: String)

Second, I think you are using your repository wrong. Instead of getting a liveData from your repository and then converting it into a MutableLiveData, you should just expose a repository function, which saves your given name.

The only thing a view should do is to observe values and expose events. Nothing more.

This could be a solution:

class YourViewModel(private val repository: IYourRepositoryInterface) : ViewModel() {
   // Token should only be observed from a view and not converted to a MutableLiveData
   val token: LiveData<String> = appPreferenceStorage.accessToken.asLiveData()

   fun updateFirstName(name: String) {
      viewModelScope.launch {
          repository.updateFirstName(name) // suspend function from your repository
      }
   }
}

Furthermore, if you want to use your token inside your viewmodel and "observe" it, you can just start collecting the flow inside a function and then use its value:

val token: Flow<String> = appPreferenceStorage.accessToken

fun someFunctionThatDoesStuffWithToken() {
    viewModelScope.launch {
      token.collect { value: String ->
        // do something with its value. E.g: Write into repository, db etc.
      }
   }
}
Andrew
  • 4,264
  • 1
  • 21
  • 65