For my firebase job I created base firebase repository to handle onSuccess and on error.
I can use it for all my firebase job but when I try to handle error I got this error.
why can I post documentReference but can't post exception.
Here is my code:
suspend inline fun <T> firebaseJob(crossinline task: () -> Task<T>): Resource<T> {
return withContext(Dispatchers.IO) {
try {
suspendCancellableCoroutine<Resource<T>> { continuation ->
task().addOnSuccessListener { documentReference ->
continuation.resume(Resource.success(documentReference))
}.addOnFailureListener { exception ->
continuation.resume(Resource.error(exception))
}
}
} catch (e: Exception) {
e.printStackTrace()
Resource.error(null)
}
}
}
Here is my Resource class
data class Resource<out T>(val status: Status, val data: T?) {
companion object {
fun <T> success(data: T?): Resource<T> {
return Resource(Status.SUCCESS, data)
}
fun <T> error(data: T?): Resource<T> {
return Resource(Status.ERROR, data)
}
fun <T> loading(data: T?): Resource<T> {
return Resource(Status.LOADING, data)
}
}
}
enum class Status {
SUCCESS,
ERROR,
LOADING
}```
Your firebaseJob
returns a Resource<T>
where T
is whatever type you use when you call this function. On the line where you have the error, you need to pass a Resource<T>
to the resume
function but you are passing a Resource<Exception>
instead.
When you call Resource.error(exception)
it creates a Resource<Exception>
because of the way you've defined your Resource
class. Your Resource
class needs to have an error
function which still returns a Resource<T>
, the same way that the Kotlin stdlib Result
function does. For that to happen, you need to make data
to be of type Any?
and then cast it to T
when you return it. See the Result
implementation to see how it's done.
An alternative way is to make Resource<T>
a sealed class or interface, and create implementation classes SuccessResource<T>
, LoadingResource<T>
and ErrorResource<T>
. The ErrorResource<T>
class would then take an Exception
object but would still be a subclass of Resource<T>
.
Your firebaseJob
code will compile ok if you replace Resource
as follows:
sealed interface Resource<out T> {
val status: Status
val data: T? get() = null
val exception: Exception? get() = null
private class LoadingResource<T>(override val data: T?) : Resource<T> {
override val status get() = Status.LOADING
}
private class SuccessResource<T>(override val data: T?) : Resource<T> {
override val status get() = Status.SUCCESS
}
private class ErrorResource<T>(override val exception: Exception?) : Resource<T> {
override val status get() = Status.ERROR
}
companion object {
fun <T> success(data: T?): Resource<T> = SuccessResource(data)
fun <T> error(exception: Exception?): Resource<T> = ErrorResource(exception)
fun <T> loading(data: T?): Resource<T> = LoadingResource(data)
}
}