I've just started implementing the MVVM architecture

I have a repository like so:

object ConfigsSSOT {

    val liveData: MutableLiveData<DataWrapper<ConfigsResponse>> = MutableLiveData<DataWrapper<ConfigsResponse>>()

    fun initConfigs() {
        liveData.value = DataWrapper.loading()

        RetrofitBuilder.createConfigs().mainConfigs(
            BuildConfig.VERSION_CODE,
            SettingsSSOT.getTimestamp(),
            TranslationsSSOT.getTimestamp(),
            CitySSOT.getTimestamp()
        ).enqueue(ApiCallback(liveData))
    }

}

In the viewmodel I have this:

    private val _configsLiveData: MutableLiveData<DataWrapper<ConfigsResponse>> = SSOT.configsSSOT.liveData
    private val _shouldUpdateLiveData: LiveData<Boolean> = Transformations.map(_configsLiveData, ::_mapShouldUpdate)

    private fun _mapShouldUpdate(configs: DataWrapper<ConfigsResponse>): Boolean {
        return (configs.status != TStatus.LOADING && configs.data?.shouldUpdate ?: false)
    }

    fun initConfigs() {// !!!!!!!! This is what I call from the Fragment to make the API call
        ConfigsSSOT.initConfigs()
    }

My problem is that, the liveData exposed in ConfigsSSOT might be used in another Fragment, another one can call initConfigs() (let's presume with other values) but being that the Repository is a singleton, it'll return the same liveData object. I don't want that.

A solution was to create a new liveData object each time the call is made, i.e.

 object ConfigsSSOT {
    
    fun initConfigs() : MutableLiveData<DataWrapper<ConfigsResponse>>{
        var liveData: MutableLiveData<DataWrapper<ConfigsResponse>> = MutableLiveData<DataWrapper<ConfigsResponse>>()
        liveData.value = DataWrapper.loading()
    
        RetrofitBuilder.createConfigs().mainConfigs(
                BuildConfig.VERSION_CODE,
                SettingsSSOT.getTimestamp(),
                TranslationsSSOT.getTimestamp(),
                CitySSOT.getTimestamp()
        ).enqueue(ApiCallback(liveData))
    
        return liveData
    }
    
}

But 2 problems occur now.

1. I will need to redo this line _shouldUpdateLiveData = Transformations.map(_configsLiveData, ::_mapShouldUpdate) as _configsLiveData in the viewModel has changed

i.e. something like this:

    fun initConfigs() : MutableLiveData<DataWrapper<ConfigsResponse>> {
        liveData = ConfigsSSOT.initConfigs()
        _shouldUpdateLiveData = Transformations.map(_configsLiveData, ::_mapShouldUpdate)
        return liveData
    }

This seems quite a bad practice, and ALSO ... if my layout (xml) retrieves and observes the liveData but then I replace that liveData instance with another one, the xml will observe something that will never get called again

2. won't that mean LiveData objects will get leaked? If I generate new ones for each call, let's say a user presses a button and I make an API call each time and generate a new LiveData object each time, what happens to the old ones?!

Help needed: I can't find any solution and best practice for the scenario: Having the same Repository to make API calls, use liveData inside Repository to send data back to the "viewModel caller" but don't instantiate a liveData for each call, instead somehow use the same one BUT at the same time don't use the same liveData call when the call is made from different viewModels.

So, so, confusing !

EDIT

Added the RetrofitBuilder because of some discussions in the comments section

object RetrofitBuilder {

    private val _okHttpClient = OkHttpClient().newBuilder()
        .connectTimeout(60, TimeUnit.SECONDS)
        .readTimeout(60, TimeUnit.SECONDS)
        .writeTimeout(60, TimeUnit.SECONDS)
        .cache(null)
        .build()

    private val _retrofitBuilderMill = Retrofit.Builder()
        .baseUrl(BuildConfig.URL_BASE + "/api/")
        .addConverterFactory(GsonConverterFactory.create())
        .client(_okHttpClient)
        .build()

    private val _retrofitBuilderPizza = Retrofit.Builder()
        .baseUrl("https://www.validator.pizza")
        .addConverterFactory(GsonConverterFactory.create())
        .client(_okHttpClient)
        .build()

    fun <S> createGenericService(serviceClass: Class<S>?): S {
        return _retrofitBuilderMill.create(serviceClass)
    }

    fun createPizza(): PizzaApiService {
        return _retrofitBuilderPizza.create(PizzaApiService::class.java)
    }

    fun createConfigs(): ConfigsApiService {
        return createGenericService(ConfigsApiService::class.java)
    }

    fun createAuth(): AuthApiService {
        return createGenericService(AuthApiService::class.java)
    }

}
0

There are 0 best solutions below