androidkotlinandroid-livedataandroid-lifecycle

new observers being created when observing lifedata after putting app to background


I have the following in my viewmodel

val currentStockPriceAsLiveData: LiveData<UiState> = stockPriceDataSource.latestStockList
        .map { listOfStock ->
            UiState.Success(listOfStock)
        }.asLiveData()

I observe this in my Activity in the onCreate method

 override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(binding.root)
        
    lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            viewModel.currentStockPriceAsLiveData.observe(this@FlowUseCase1Activity) { uiState ->
                if (uiState != null) {
                    if(uiState is UiState.Success) {
                        Timber.d("Received ${uiState.stockList.first()}")
                    }
                    render(uiState)
                }
            }
        }
    }
}

I am using repeatOnLifeCycle to only observe when the lifecycle is at least STARTED state. This works as if I put the app in the background it will stop observing.

However, the problem is when I bring the app back to the foreground it will trigger duplicated emissions. And when I put the app to the background a second time it will trigger triple emissions.

From my log:

00:00:05.274 23476-23476  D  Received Stock(rank=1, name=Apple, symbol=AAPL, marketCap=2.37819317E12, country=United States, currentPrice=142.95015, currency=DOLLAR, priceTrend=UNKNOWN)
00:00:05.275 23476-23476  D  Received Stock(rank=1, name=Apple, symbol=AAPL, marketCap=2.37819317E12, country=United States, currentPrice=142.95015, currency=DOLLAR, priceTrend=UNKNOWN)
00:00:05.276 23476-23476  D  Received Stock(rank=1, name=Apple, symbol=AAPL, marketCap=2.37819317E12, country=United States, currentPrice=142.95015, currency=DOLLAR, priceTrend=UNKNOWN)

As you can see its like its triggering 3 times at the same time.

I think it is because when I put the app to the background the viewmodel has not been destroyed, so when I put the app back in the foreground it creates subsequent observers.

Is there a way to prevent this?


Solution

  • You don't have to manage the lifecycle of LiveData. LiveData manages its own lifecycle. It will pause or resume based on lifecycle of containing Activity and Fragment.

    Use LiveData like this in onCreate()

    viewModel.currentStockPriceAsLiveData.observe(this@FlowUseCase1Activity) { uiState ->
                if (uiState != null) {
                    if(uiState is UiState.Success) {
                        Timber.d("Received ${uiState.stockList.first()}")
                    }
                    render(uiState)
                }
            }
    

    I don't know exactly why it's duplicating. It may be because you attach a new observer each time the lifecycle reach STARTED STATE. LiveData does not need to be attached each time the lifecycle changes. It manages its own lifecycle. Call live data as shown above in onCreate() just once.