Home > Net >  Kotlin Flow out generic
Kotlin Flow out generic

Time:04-30

I am using flow{} builder to call the api and then emit() the response to ViewModel. I add return type of flow as Flow<Resource<List<RemoteData>>>. However, at some places in emit(), the Android Studio throws

error : Not enough information to infer type variable T

Because the emit(Resource.Error(message = "Couldn't reach server, check your internet connection.")) is expecting values of type List<RemoteData> Please see my Resource class below

sealed class Resource<T>(val data: T? = null, val message: String? = null) {
    class Loading<T>(data: T? = null): Resource<T>(data)
    class Success<T>(data: T?): Resource<T>(data)
    class Error<T>(message: String, data: T? = null): Resource<T>(data, message)
}

My question, Is it safe to change emit to

emit(Resource.Error(
            message = "Couldn't reach server, check your internet connection.",
            data = null
        ))

And flow's return type as Flow<Resource<out List<RemoteData>>> ?

CodePudding user response:

Kotlin has declaration site variance. I would put out at the Resource class declaration. Then when you declare your type Flow<Resource<List<RemoteData>>>, it will already be implicitly out List<RemoteData>.

Also, your Resource classes look convoluted to me. If data is the loaded resource, it should not be part of the Loading or Error classes. Why force every instance of Loading and Error to carry a meaningless null data value? Likewise, the message should not be part of the Loading and Success cases.

I would rewrite your sealed class as a sealed interface (since it has no shared state between types) like this, and take advantage of data class features as well. Loading can be an object because it doesn't need to hold state. Loading and Error can both be Resource<Nothing> since the type T is irrelevant to any specific instance of them. That way you won't have to needlessly specify types when using them, like having to put <RemoteData> after is Resource or is Error in a when statement.

sealed interface Resource<out T> {
    object Loading: Resource<Nothing>
    data class Success<out T>(val data: T): Resource<T>
    data class Error(val message: String): Resource<Nothing>
}

This version of the sealed classes will be much easier to use. The compiler will be more lenient with how and where you need to specify generic types.

  • Related