From c33ea64da496358bb2fbee2fa068cd33531de47c Mon Sep 17 00:00:00 2001 From: xenia Date: Sat, 6 Jun 2026 15:21:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=97=20ReactiveCats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 + .../otus/homework/reactivecats/CatsService.kt | 4 +- .../homework/reactivecats/CatsViewModel.kt | 67 +++++++++++++------ .../otus/homework/reactivecats/DiContainer.kt | 3 + .../reactivecats/LocalCatFactsGenerator.kt | 14 ++-- .../homework/reactivecats/MainActivity.kt | 1 - gradle/libs.versions.toml | 2 + 7 files changed, 64 insertions(+), 28 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4a3a24af..e42590fc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,4 +47,5 @@ dependencies { implementation libs.picasso implementation libs.rxjava implementation libs.rxandroid + implementation libs.retrofit.rxjava.adapter } diff --git a/app/src/main/java/otus/homework/reactivecats/CatsService.kt b/app/src/main/java/otus/homework/reactivecats/CatsService.kt index f30b3aac..89c32878 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsService.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsService.kt @@ -1,11 +1,11 @@ package otus.homework.reactivecats -import retrofit2.Call +import io.reactivex.Single import retrofit2.http.GET 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 d62eaf97..570cafdd 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt @@ -5,40 +5,65 @@ 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.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import retrofit2.HttpException +import java.net.ConnectException +import java.net.SocketException +import java.net.UnknownHostException +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() + 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 - ) + getFacts() + } + + fun getFacts() { + val disposable: Disposable = Flowable + .interval(2, TimeUnit.SECONDS) + .flatMapSingle { + catsService + .getCatFact() + .onErrorResumeNext( + localCatFactsGenerator.generateCatFact() ) - } } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { response -> _catsLiveData.value = Success(response) }, + { throwable -> + when (throwable) { + is UnknownHostException, is ConnectException, is SocketException -> + _catsLiveData.value = ServerError - override fun onFailure(call: Call, t: Throwable) { - _catsLiveData.value = ServerError - } - }) + is HttpException -> _catsLiveData.value = Error("${throwable.code()}") + + else -> _catsLiveData.value = Error( + throwable.message + ?: context.getString(R.string.default_error_text) + ) + } + } + ) + compositeDisposable.add(disposable) } - fun getFacts() {} + override fun onCleared() { + compositeDisposable.clear() + super.onCleared() + } } class CatsViewModelFactory( diff --git a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt index bbccfc7b..02368945 100644 --- a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt +++ b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt @@ -2,6 +2,8 @@ package otus.homework.reactivecats import android.content.Context import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +//import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory class DiContainer { @@ -11,6 +13,7 @@ class DiContainer { //.baseUrl("https://cat-fact.herokuapp.com/facts/") .baseUrl("https://catfact.ninja/") .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build() } diff --git a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt index 4481062e..bce1771b 100644 --- a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt +++ b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt @@ -3,7 +3,7 @@ package otus.homework.reactivecats import android.content.Context import io.reactivex.Flowable import io.reactivex.Single -import kotlin.random.Random +import java.util.concurrent.TimeUnit class LocalCatFactsGenerator( private val context: Context @@ -15,7 +15,8 @@ class LocalCatFactsGenerator( * обернутую в подходящий стрим(Flowable/Single/Observable и т.п) */ fun generateCatFact(): Single { - return Single.never() + val facts = context.resources.getStringArray(R.array.local_cat_facts) + return Single.just(Fact(facts.random())) } /** @@ -24,7 +25,12 @@ class LocalCatFactsGenerator( * Если вновь заэмиченный Fact совпадает с предыдущим - пропускаем элемент. */ fun generateCatFactPeriodically(): Flowable { - val success = Fact(context.resources.getStringArray(R.array.local_cat_facts)[Random.nextInt(5)]) - return Flowable.empty() + val facts = context.resources.getStringArray(R.array.local_cat_facts) + return Flowable + .interval(2, TimeUnit.SECONDS) + .map { + Fact(facts.random()) + } + .distinctUntilChanged() } } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/reactivecats/MainActivity.kt b/app/src/main/java/otus/homework/reactivecats/MainActivity.kt index 8ec95711..b5d72a5b 100644 --- a/app/src/main/java/otus/homework/reactivecats/MainActivity.kt +++ b/app/src/main/java/otus/homework/reactivecats/MainActivity.kt @@ -4,7 +4,6 @@ import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import androidx.activity.viewModels -import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar class MainActivity : AppCompatActivity() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 46c95785..58f50aa6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ picasso = "2.71828" retrofit = "2.9.0" rxandroid = "2.1.1" rxjava = "2.2.21" +retrofit-rxjava-adapter = "2.9.0" [libraries] core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } @@ -33,6 +34,7 @@ retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" } rxandroid = { module = "io.reactivex.rxjava2:rxandroid", version.ref = "rxandroid" } rxjava = { module = "io.reactivex.rxjava2:rxjava", version.ref = "rxjava" } +retrofit-rxjava-adapter = { module = "com.squareup.retrofit2:adapter-rxjava2", version.ref = "retrofit-rxjava-adapter" } [bundles] network = ["okhttp", "okhttp-logging-interceptor", "retrofit", "retrofit-converter-gson"]