diff --git a/app/src/main/java/otus/homework/reactivecats/CatsService.kt b/app/src/main/java/otus/homework/reactivecats/CatsService.kt index f30b3aa..e98252f 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsService.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsService.kt @@ -1,5 +1,6 @@ package otus.homework.reactivecats +import io.reactivex.Single import retrofit2.Call import retrofit2.http.GET @@ -7,5 +8,5 @@ interface CatsService { //@GET("random?animal_type=cat") @GET("fact") - fun getCatFact(): Call + fun getCatFact(): Single } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt index d62eaf9..d086d15 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt @@ -5,40 +5,127 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import io.reactivex.Flowable +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import retrofit2.HttpException +import java.io.IOException +import java.util.concurrent.TimeUnit class CatsViewModel( - catsService: CatsService, - localCatFactsGenerator: LocalCatFactsGenerator, - context: Context + private val catsService: CatsService, + private val localCatFactsGenerator: LocalCatFactsGenerator, + private val context: Context ) : ViewModel() { private val _catsLiveData = MutableLiveData() val catsLiveData: LiveData = _catsLiveData + private val compositeDisposable = CompositeDisposable() + + private var isPeriodicUpdatesActive = false + init { - catsService.getCatFact().enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful && response.body() != null) { - _catsLiveData.value = Success(response.body()!!) - } else { - _catsLiveData.value = Error( - response.errorBody()?.string() ?: context.getString( - R.string.default_error_text - ) - ) + getSingleFact() + } + + fun getFacts() { + if (isPeriodicUpdatesActive) { + stopPeriodicUpdates() + return + } + + isPeriodicUpdatesActive = true + + val disposable = Flowable.interval(0, 2, TimeUnit.SECONDS) + .flatMapSingle { _ -> + catsService.getCatFact() + .subscribeOn(Schedulers.io()) + .onErrorResumeNext { throwable: Throwable -> + if (throwable is IOException || throwable is HttpException) { + localCatFactsGenerator.generateCatFact() + .subscribeOn(Schedulers.io()) + } else { + Single.error(throwable) + } + } + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { fact -> + _catsLiveData.value = Success(fact) + }, + { throwable -> + handleError(throwable) + isPeriodicUpdatesActive = false + } + ) + + compositeDisposable.add(disposable) + } + + fun getSingleFact() { + val disposable = catsService.getCatFact() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { fact -> + _catsLiveData.value = Success(fact) + }, + { throwable -> + handleError(throwable) } + ) + + compositeDisposable.add(disposable) + } + + fun stopPeriodicUpdates() { + isPeriodicUpdatesActive = false + compositeDisposable.clear() + } + + private fun handleError(throwable: Throwable) { + when (throwable) { + is HttpException -> { + val errorBody = throwable.response()?.errorBody()?.string() + ?: context.getString(R.string.default_error_text) + _catsLiveData.value = Error(errorBody) + } + + is IOException -> { + getLocalFactAsFallback() } - override fun onFailure(call: Call, t: Throwable) { - _catsLiveData.value = ServerError + else -> { + _catsLiveData.value = Error(context.getString(R.string.default_error_text)) } - }) + } + } + + private fun getLocalFactAsFallback() { + val disposable = localCatFactsGenerator.generateCatFact() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { fact -> + _catsLiveData.value = Success(fact) + }, + { error -> + _catsLiveData.value = ServerError + } + ) + + compositeDisposable.add(disposable) } - fun getFacts() {} + override fun onCleared() { + super.onCleared() + compositeDisposable.clear() + } } class CatsViewModelFactory( diff --git a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt index 4481062..b20b47c 100644 --- a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt +++ b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt @@ -3,6 +3,7 @@ package otus.homework.reactivecats import android.content.Context import io.reactivex.Flowable import io.reactivex.Single +import java.util.concurrent.TimeUnit import kotlin.random.Random class LocalCatFactsGenerator( @@ -15,7 +16,12 @@ class LocalCatFactsGenerator( * обернутую в подходящий стрим(Flowable/Single/Observable и т.п) */ fun generateCatFact(): Single { - return Single.never() + return Single.fromCallable { + val factsArray = context.resources.getStringArray(R.array.local_cat_facts) + val randomIndex = Random.nextInt(factsArray.size) + val randomFactText = factsArray[randomIndex] + Fact(randomFactText) + } } /** @@ -24,7 +30,15 @@ class LocalCatFactsGenerator( * Если вновь заэмиченный Fact совпадает с предыдущим - пропускаем элемент. */ fun generateCatFactPeriodically(): Flowable { - val success = Fact(context.resources.getStringArray(R.array.local_cat_facts)[Random.nextInt(5)]) - return Flowable.empty() + val factsArray = context.resources.getStringArray(R.array.local_cat_facts) + + return Flowable.interval(2_000, TimeUnit.MILLISECONDS) + .map { + val randomIndex = Random.nextInt(factsArray.size) + val randomFactText = factsArray[randomIndex] + Fact(randomFactText) + } + .distinctUntilChanged() + .onBackpressureLatest() } } \ No newline at end of file