I added Hilt to my project and now LiveData
returns wrong Object type
. Maybe I made some wrong changes in my code.
getAllCurrencies
returns LiveData<Resource<Unit>>
but it should LiveData<Resource<Currencies>>
ViewModel:
class SplashScreenViewModel @ViewModelInject constructor(
private val roomDatabaseRepository: RoomDatabaseRepository,
private val retrofitRepository: RetrofitRepository) : ViewModel() {
fun getAllCurrencies(mainCurrency: String) = liveData(Dispatchers.IO) {
emit(Resource.loading(data = null))
try {
emit(Resource.success(data = retrofitRepository.getAllCurrencies(mainCurrency)))
} catch (exception: Exception) {
emit(Resource.error(data = null, message = exception.message ?: "Error Occurred!"))
}
}
Repository: (It returns good type)
class RetrofitRepository @Inject constructor(val currenciesApiHelper: CurrenciesApiHelper) {
suspend fun getAllCurrencies(mainCurrency: String) {
currenciesApiHelper.getAllCurrencies(mainCurrency)
}
You should return currenciesApiHelper.getAllCurrencies(mainCurrency)
in to Repository.
(optional) Following is the way I do it with MVVM:
I'll assume that you have Currency as a model declared somewhere already.
Status
sealed class Status<out T> {
class Loading<out T> : Status<T>()
data class Success<out T>(val data: T) : Status<T>()
data class Failure<out T>(val exception: Exception) : Status<T>()
}
Fragment/Presentation Layer
viewModel.fetchCurrencies(mainCurrency)
.observe(viewLifecycleOwner, Observer { result ->
when (result) {
is Status.Loading<*> -> {
//display a ProgressBar or so
}
is Status.Success<*> -> {
//Status.Success<*> can also be Status.Success<ArrayList<Currency>>
//hide the ProgressBar
val currencies = result.data as ArrayList<Currency>
}
is Status.Failure<*> -> {
//log the exception
}
}
})
ViewModel
private val repo = Repository()
@ExperimentalCoroutinesApi
fun fetchCurrencies(mainCurrency: String): LiveData<Status<MutableList<Currency>>> =
liveData(Dispatchers.IO) {
emit(Status.Loading())
try {
repo.getCurrencies(mainCurrency).collect {
emit(it)
}
} catch (e: Exception) {
emit(Status.Failure(e))
Log.e("ERROR:", e.message!!)
}
}
Repository (single datasource)
Using Firestore instead here as I'm not 100% certainly sure about your way.
Do what retrofitRepository.getAllCurrencies(mainCurrency)
should do and then offer the result.
private val fs: FirebaseFirestore = Firebase.firestore
@ExperimentalCoroutinesApi
fun getCurrencies(mainCurrency: String): Flow<Status<MutableList<Currency>>> = callbackFlow {
val subscription = fs.collection("currencies")
.addSnapshotListener { snapshot, _ ->
if (snapshot != null) {
val result = snapshot.toObjects(Currency::class.java)
offer(Success(result))
}
}
awaitClose { subscription.remove() }
}
Using coroutines is by the way quite sweet. Have a look here:
Learn advanced coroutines with Kotlin Flow and LiveData
Android Coroutines: How to manage async tasks in Kotlin
Hope it helps :)