Reputation: 117
In my code I would like to create a method in an abstract class, which returns some Observable. Then implementation of this abstract class would return Observable of certain (specified) type. Unfortunately Android Studio will return an error "Type mismatch" in implementation method():
My MockDrawerList.getList()
returns Observable<DrawerItemEntity>
please focus on execute()
and buildUseCaseObservable
public abstract class UseCase(threadExecutor: ThreadExecutor,
postExecutionThread: PostExecutionThread) {
private val threadExecutor: ThreadExecutor
private val postExecutionThread: PostExecutionThread
private var subscription: Subscription = Subscriptions.empty()
init {
this.postExecutionThread = postExecutionThread
this.threadExecutor = threadExecutor
}
protected abstract fun buildUseCaseObservable(): Observable<Any>
public fun execute(useCaseSubsriber: Subscriber<Any>) {
subscription = buildUseCaseObservable()
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler())
.subscribe(useCaseSubsriber)
}
public fun unsubsribe() {
if (!subscription.isUnsubscribed())
subscription.unsubscribe()
}
}
Inject
class GetDrawerListUseCase(threadExecutor: ThreadExecutor,
postExecutionThread:PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
override fun buildUseCaseObservable(): Observable<Any> {
return MockDrawerList.getList()
}
}
Upvotes: 1
Views: 3294
Reputation: 32776
Even though String
is a subtype of Any
, Observable<String>
is not considered a subtype of Observable<Any>
in Kotlin. You should use use-site variance: change buildUseCaseObservable
's return type to Observable<out Any>
or Observable<*>
(the latter is equivalent to Observable<out Any?>
) and the code should compile.
Why doesn't inheritance for generic types work automatically based on their type parameters? This is a problem best explained by Joshua Bloch in Effective Java, Item 28: Use bounded wildcards to increase API flexibility. To put very simply, this can work only when the type is guaranteed not to consume instances of its type parameters, i.e. if a class with a generic parameter T
has no methods taking T
as a parameter. One way this can be enforced in Kotlin is by declaration-site variance, which is the case for example for collection interfaces (kotlin.Collection
, kotlin.List
, ...).
However, Observable
is of course not a Kotlin class, so the compiler has no way of knowing that Observable<String>
can be used safely where an Observable<Any>
is expected. So we have to manually tell the compiler that we're OK with using only a subset of features of Observable<T>
that don't take T
as a parameter, so that we will get the nice inheritance instead. This "subset type" is called a type projection in Kotlin and the technique is called use-site variance.
You can read more about declaration- and use-site variance in Kotlin in the official language documentation, section Generics.
Upvotes: 7