I am trying to get an object from a MutableLiveData<Resource<ObjectIWant>>
to a var hereIwantTheObject : ObjectIWant
in my HomeFragment, apparently use the Resource class is the recommended way if you use coroutines and LiveData. The thing is that I want this object on my variable and disatached from MutableLiveData, when I try it says the variable hasn't been initialized. Here my classes and what I have tried
ViewModel class:
class HomeFragmentViewModel : ViewModel() {
val mutableVar: MutableLiveData<Resource<ObjectIwant>> = MutableLiveData()
init {
getObjectIwantData()
}
fun getObjectIwantData() = viewModelScope.launch {
mutableVar.postValue(Resource.Loading())
val response = AppRepository().getObjectIwantDataInRepository()
mutableVar.postValue(handleResponse(response))
}
private fun handleResponse(response: Response<ObjectIwant>): Resource<ObjectIwant> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
return Resource.Success(resultResponse)
}
}
return Resource.Error(response.message())
}
HomeFragment class and where I am trying to get the info:
class HomeFragment : Fragment() {
lateinit var viewModel: HomeFragmentViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
viewModel = ViewModelProvider(this).get(HomeFragmentViewModel::class.java)
binding.lifecycleOwner = this
var hereIwantTheObject: ObjectIwant? = null
viewModel.brastlewarkTownData.observe(viewLifecycleOwner, Observer { response ->
response.data?.let { brastlewarkTown ->
hereIwantTheObject = brastlewarkTown
}
})
Log.i(TAG, "onCreateView: ${hereIwantTheObject!!.name")
return binding.root
}
}
Here the Resource class:
sealed class Resource<T>(
val data: T? = null,
val message: String? = null
) {
class Success<T>(data: T) : Resource<T>(data)
class Error<T>(message: String, data: T? = null) : Resource<T>(data, message)
class Loading<T> : Resource<T>()
}
When onCreateView()
is executed, several things happen:
var hereIwantTheObject
is declared and initialised with null
LiveData<Resource<ObjectIwant>>
object is registerednull
but you promise it is not null
when writing to LogcatBut why is hereIwantTheObject still null
? That's because the observation results for any LiveData
objects can only come in on the UI thread after execution of the current function onCreateView()
has finished.
At this point however the local variable will have been discarded, so if you want to be able to assign a value to it later on you need to make it a property:
private var hereIwantTheObject: String? = null
Now if you delete the line with the local declaration for hereIwantTheObject and move the Log.i(...)
statement to the block which is executed if there are changes to the LiveData
object, everything will work as desired
response.data?.let { brastlewarkTown ->
hereIwantTheObject = brastlewarkTown
Log.i(TAG, "onCreateView: ${hereIwantTheObject!!.name}")
}