I am building a stock comparison feature in my Android app where users can:
Current Implementation:
Here’s my current code setup:
class StockViewModel : ViewModel() {
private val _stockDetails = MutableLiveData<Stock>()
val stockDetails: LiveData<Stock> = _stockDetails
fun fetchStockDetails(ticker: String) {
viewModelScope.launch {
try {
val stock = repository.getStockDetails(ticker)
_stockDetails.value = stock
} catch (e: Exception) {
Log.e("StockViewModel", "Error fetching stock details", e)
}
}
}
}
This view model fetches one stock at a time. How can I get new stock details while keeping previous and refreshing each stock to get fresh data using the refresh button.
You need to store a list of stocks somewhere. You could do that in the view model as you already do it with the single stock you have so far, but this is something that should be stored in the repository instead.
You would usually use a Flow for that:
class Repository {
private val _stocks = MutableStateFlow<List<Stock>>(emptyList())
val stocks = _stocks.asStateFlow()
suspend fun loadStockDetails(ticker: String) {
try {
val stock = getStockDetails(ticker)
_stocks.update { it + stock }
} catch (e: Exception) {
Log.e("StockViewModel", "Error fetching stock details", e)
}
}
private suspend fun getStockDetails(ticker: String): Stock {
// ...
}
}
The view model then only needs to convert the flow to a LiveData:
val stockDetails: LiveData<List<Stock>> = repository.stocks.asLiveData()
Better yet, just pass the flow through to the UI (i.e. val stockDetails = repository.stocks
) and let the UI directly collect the flow, removing the need for LiveData altogether. If you use Compose for your UI that is especially simple:
val stocks: List<Stock> by viewModel.stockDetails.collectAsStateWithLifecycle()
Now that loading stocks is encapsualted in the repository you can add additional logic there, for example what should happen when the stock was already loaded or a way to persist the data in a database so it doesn't need to be reloaded every time the app starts.