Jose Garcia
Jose Garcia

Reputation: 158

View not being updated using LiveData, a TimerTask and Retrofit

I have to make a GET request every second and I have to update the UI with the incoming fresh data.

I managed to get the repeating network request working using a Timer. I can see okhttp logs showing the repeating responses with fresh data each second.

However, the UI is not updating with the new data. It only shows the data from the first request. I have tried to implement MVVM calling the network and returning a LiveData to be observed in the fragment.

Edit: I just noticed the new data is being appended to the list as the recyclerview now is growing and growing every second with new items.

ViewModel

class RatesViewModel : ViewModel() {
    private val _rates = MutableLiveData<RatesResponse>()

    val rates : LiveData<RatesResponse>
        get() = _rates

    fun init(base: String) {
        timer("NetworkRequest",false, 0, 1000) {
            viewModelScope.launch {
                _rates.postValue(RatesRepository().getRates(base))

            }
        }
    }
}

Fragment

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)

viewModel = ViewModelProvider(this).get(RatesViewModel::class.java)

viewModel.init("EUR")

    val ratesLiveData = viewModel.rates

    ratesLiveData.observe(viewLifecycleOwner, Observer { response ->
        addElements(response.rates)

        if (ratesAdapter == null) {
            setUpRecyclerView()
        } else {
            ratesAdapter!!.notifyDataSetChanged()

        }
    })

    setUpRecyclerView()
}

Add element function

private fun addElements(allRates: Rates) {
        ratesList.add(Currency(
            "EUR", "Euro", R.drawable.eur, 1.00))
        ratesList.add(Currency(
            "AUD", "Australian Dollar", R.drawable.aud, allRates.AUD))
        ratesList.add(Currency(
            "BGN", "Bulgarian Lev", R.drawable.bgn, allRates.BGN))
        ratesList.add(Currency(
            "BRL", "Brazilian Real", R.drawable.brl, allRates.BRL))
        ratesList.add(Currency(
            "CAD", "Canadian Dollar", R.drawable.cad, allRates.CAD))
        ratesList.add(Currency(
            "CHF", "Swiss franc", R.drawable.chf, allRates.CHF))
        ratesList.add(Currency(
            "CNY", "Chinese Yuan", R.drawable.cny, allRates.CNY))
        ratesList.add(Currency(
            "CZK", "Czech Koruna", R.drawable.czk, allRates.CZK))
        ratesList.add(Currency(
            "DKK", "Danish Krone", R.drawable.dkk, allRates.DKK))
        ratesList.add(Currency(
            "GBP", "British Pound", R.drawable.gbp, allRates.GBP))
        ratesList.add(Currency(
            "HKD", "Hong Kong Dollar", R.drawable.hkd, allRates.HKD))
        ratesList.add(Currency(
            "HRK", "Croatian Kuna", R.drawable.hrk, allRates.HRK))
        ratesList.add(Currency(
            "HUF", "Hungarian Forint", R.drawable.huf, allRates.HUF))
        ratesList.add(Currency(
            "IDR", "Indonesian Rupiah", R.drawable.idr, allRates.IDR))
        ratesList.add(Currency(
            "ILS", "Israeli Shekel", R.drawable.ils, allRates.ILS))
        ratesList.add(Currency(
            "INR", "Indian Rupee", R.drawable.eur, allRates.INR))
        ratesList.add(Currency(
            "ISK", "Icelandic Króna", R.drawable.isk, allRates.ISK))
        ratesList.add(Currency(
            "JPY", "Japanese Yen", R.drawable.jpy, allRates.JPY))
        ratesList.add(Currency(
            "KRW", "South Korean Won", R.drawable.krw, allRates.KRW))
        ratesList.add(Currency(
            "MXN", "Mexican Peso", R.drawable.mxn, allRates.MXN))
        ratesList.add(Currency(
            "MYR", "Malaysian Ringgit", R.drawable.myr, allRates.MYR))
        ratesList.add(Currency(
            "NOK", "Norwegian Krone", R.drawable.nok, allRates.NOK))
        ratesList.add(Currency(
            "NZD", "Bulgarian Lev", R.drawable.bgn, allRates.BGN))
        ratesList.add(Currency(
            "PHP", "Philippine Peso", R.drawable.php, allRates.PHP))
        ratesList.add(Currency(
            "PLN", "Polish Złoty", R.drawable.pln, allRates.PLN))
        ratesList.add(Currency(
            "RON", "Romanian Leu", R.drawable.ron, allRates.RON))
        ratesList.add(Currency(
            "RUB", "Russian Rouble", R.drawable.rub, allRates.RUB))
        ratesList.add(Currency(
            "SEK", "Swedish krona", R.drawable.sek, allRates.SEK))
        ratesList.add(Currency(
            "SGD", "Singapore Dollar", R.drawable.sgd, allRates.SGD))
        ratesList.add(Currency(
            "THB", "Thai Baht", R.drawable.thb, allRates.THB))
        ratesList.add(Currency(
            "USD", "United States Dollar", R.drawable.usd, allRates.USD))
        ratesList.add(Currency(
            "ZAR", "South African Rand", R.drawable.zar, allRates.ZAR))
    }

Upvotes: 0

Views: 471

Answers (2)

Jose Garcia
Jose Garcia

Reputation: 158

I fixed it by calling the clear() method on the list at start of the addElemenet() function.

I don't think this is the right thing to do, though.

Upvotes: 0

Karan Dhillon
Karan Dhillon

Reputation: 1234

Did some formatting to separate different parts of logic

VIEWMODEL

class RatesViewModel : ViewModel() {
    private val _rates = MutableLiveData<RatesResponse>()
    val rates : LiveData<RatesResponse>
        get() = _rates

    fun setupTimer(zone: String) = viewModelScope.launch { 
        timer("NetworkRequest",false, 0, 1000) { 
            val latestRates = getRates(zone)
            _rates.postValue(latestRates) 
            } 
        }

    suspend fun getRates(zone: String) = RatesRepository().getRates(zone)
}

FRAGMENT

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    viewModel = ViewModelProvider(this).get(RatesViewModel::class.java)

    viewModel.setupTimer("EUR")
    val ratesLiveData = viewModel.rates

    ratesLiveData.observe(viewLifecycleOwner, Observer { response ->
        addElements(response.rates)
    })

    /**
    * Your recyclerView should not get setup again and again anytime a new value is posted in the livedata.
    */

    if (ratesAdapter == null) setUpRecyclerView()
    else ratesAdapter!!.notifyDataSetChanged()
}

You mentioned that the new data is getting appended at the end of the list i.e. allRates, in that case instead of ADD use UPDATE, as ADD will not remove the old elements.

Upvotes: 1

Related Questions