2016-02-26 2 views
1

Я хочу, чтобы мой NewsListSubscriber наследовал от подписчика RxJava, который использует общий тип, но я получаю ошибку «Тип несоответствия» при вызове метода выполнения UseCase. Я много раз читал страницу генериков из документации Kotlin, но я не могу найти решение.Kotlin: Как наследовать от RxJava Subscriber

Вот мой UseCase:

abstract class UseCase(private val threadExecutor: IThreadExecutor, 
         private val postExecutionThread: IPostExecutionThread) { 

    private var subscription = Subscriptions.empty() 

    fun execute(UseCaseSubscriber: rx.Subscriber<Any>) { 
     subscription = buildUseCaseObservable() 
       .subscribeOn(Schedulers.from(threadExecutor)) 
       .observeOn(postExecutionThread.getScheduler()) 
       .subscribe(UseCaseSubscriber) 
    } 

    protected abstract fun buildUseCaseObservable(): Observable<out Any> 

    fun unsubscribe() { 
     if (!subscription.isUnsubscribed) { 
      subscription.unsubscribe() 
     } 
    } 
} 

А вот как я это называю:

override fun loadNewsList() { 
    getNewsListInteractor.execute(NewsListSubscriber()) 
} 

private inner class NewsListSubscriber : rx.Subscriber<List<NewsModel>>() { 
    override fun onCompleted() {// TODO} 

    override fun onError(e: Throwable) {// TODO} 

    override fun onNext(t: List<NewsModel>) {// TODO} 
} 

Ошибка

«Несоответствие типа Требуемый:. Rx.Subscriber. Найдено: Презентаторы.НовостиListPresenter.NewsListSubscriber "

в строке «выполнить (NewsListSubscriber()). Я пробовал играть с ключевыми словами «in» и «out», но у меня все еще такая же ошибка.

+0

Является ли класс подписчика в методе так же, как и суперкомпоном rx.Subscriber во внутреннем классе? Просто проверить, не могу сказать точно здесь, не видя импорт. –

+0

Да, я обновил свой код, чтобы использовать rx.Subscriber в обоих случаях. – MickaelG

+0

'Подписчик ' является эквивалентом 'Subscriber', который не совместим с более конкретными обозначениями. Решение состоит в том, чтобы ввести общий тип, который используется для вывода 'execute()' input и 'buildUsecase'. – Kiskae

ответ

2

На самом деле существует лучший способ решить эту проблему. Я столкнулся с той же проблемой, и тип, введенный внутри каждого производного класса подписчика, не был вариантом.

Просто обновите абстрактный класс UseCase с параметром общего типа.

abstract class UseCase<T>(private val threadExecutor: IThreadExecutor, 
        private val postExecutionThread: IPostExecutionThread) { 

    private var subscription = Subscriptions.empty() 

    fun execute(UseCaseSubscriber: rx.Subscriber<T>) { 
     subscription = buildUseCaseObservable() 
       .subscribeOn(Schedulers.from(threadExecutor)) 
       .observeOn(postExecutionThread.getScheduler()) 
       .subscribe(UseCaseSubscriber) 
    } 

    protected abstract fun buildUseCaseObservable(): Observable<T> 

    fun unsubscribe() { 
     if (!subscription.isUnsubscribed) { 
      subscription.unsubscribe() 
     } 
    } 
} 

Когда вы объявляете производные классы UseCase, используйте свой конкретный тип для общего параметра при вызове суперкласса.

class ConcreteUseCase(val threadExecutor: IThreadExecutor, 
       val postExecutionThread: IPostExecutionThread) 
       : UseCase<ConcreteType>(threadExecutor, postExecutionThread) 

Делая так, вы можете использовать типизированные Абонент в вашем execute вызова.

getNewsListInteractor.execute(NewsListSubscriber()) 

... 

private inner class NewsListSubscriber : rx.Subscriber<List<NewsModel() { 
    override fun onCompleted() {// TODO} 

    override fun onError(e: Throwable) {// TODO} 

    override fun onNext(t: List<NewsModel>) {// TODO} 
} 
0

Я нашел решение, которое довольно просто на самом деле: мой класс NewsListSubscriber должен простирается от rx.Subscriber < Любой > вместо rx.Subscriber <MyWantedClass>. Это означает, что мне нужно передать полученные объекты в желаемый тип.

private inner class NewsListSubscriber : DefaultSubscriber<Any>() { 

    override fun onCompleted() {} 

    override fun onError(e: Throwable) {} 

    override fun onNext(t: Any?) { 
     val newsList = t as List<News> 
     ... 
    } 
} 

В Java актеры сделаны в фоновом режиме, но в Котлине нам нужно сделать это сами.

Я также удалил все ключевые слова «in» или «out» в моем классе UseCase.

Смежные вопросы