From 369f575338d517f34f54a46fa2916f20b0576bd0 Mon Sep 17 00:00:00 2001 From: YURY TILMAN Date: Sat, 11 Apr 2026 22:12:39 +0300 Subject: [PATCH] Home task implement --- app/build.gradle | 1 + .../otus/homework/reactivecats/CatsService.kt | 4 +- .../homework/reactivecats/CatsViewModel.kt | 67 +++++++++++-------- .../otus/homework/reactivecats/DiContainer.kt | 4 +- .../reactivecats/LocalCatFactsGenerator.kt | 22 +++--- .../homework/reactivecats/MainActivity.kt | 4 +- gradle/libs.versions.toml | 1 + 7 files changed, 61 insertions(+), 42 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4a3a24af..3c21e9e7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,5 +46,6 @@ dependencies { implementation libs.gson implementation libs.picasso implementation libs.rxjava + implementation libs.retrofit.rxjava implementation libs.rxandroid } 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..a032908f 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt @@ -1,55 +1,68 @@ package otus.homework.reactivecats -import android.content.Context 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 + class CatsViewModel( - catsService: CatsService, - localCatFactsGenerator: LocalCatFactsGenerator, - context: Context + private val catsService: CatsService, + private val localCatFactsGenerator: LocalCatFactsGenerator, ) : ViewModel() { private val _catsLiveData = MutableLiveData() val catsLiveData: LiveData = _catsLiveData + private val disposable = 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 - ) - ) - } - } - - override fun onFailure(call: Call, t: Throwable) { - _catsLiveData.value = ServerError - } - }) + getFacts() + } + + private fun getFacts() { + disposable.add( + localCatFactsGenerator.generateCatFactPeriodically() + .flatMap(::handleFactRequest) + .distinctUntilChanged() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(::onFactSuccess, ::onFactError) + ) + } + + private fun handleFactRequest(localFact: Fact): Flowable { + return catsService.getCatFact() + .onErrorResumeNext { Single.just(localFact) } + .toFlowable() } - fun getFacts() {} + private fun onFactSuccess(fact: Fact) { + _catsLiveData.value = Success(fact) + } + + private fun onFactError(throwable: Throwable) { + _catsLiveData.value = Error(throwable.message!!) + } + + + override fun onCleared() { + super.onCleared() + disposable.clear() + } } class CatsViewModelFactory( private val catsRepository: CatsService, private val localCatFactsGenerator: LocalCatFactsGenerator, - private val context: Context ) : ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T = - CatsViewModel(catsRepository, localCatFactsGenerator, context) as T + CatsViewModel(catsRepository, localCatFactsGenerator) as T } sealed class Result diff --git a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt index bbccfc7b..85a4a1ea 100644 --- a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt +++ b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt @@ -2,6 +2,7 @@ package otus.homework.reactivecats import android.content.Context import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory class DiContainer { @@ -11,10 +12,11 @@ class DiContainer { //.baseUrl("https://cat-fact.herokuapp.com/facts/") .baseUrl("https://catfact.ninja/") .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build() } - val service by lazy { retrofit.create(CatsService::class.java) } + val service: CatsService by lazy { retrofit.create(CatsService::class.java) } fun localCatFactsGenerator(context: Context) = LocalCatFactsGenerator(context) } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt index 4481062e..e5be263e 100644 --- a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt +++ b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt @@ -3,28 +3,32 @@ 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( private val context: Context ) { + private val localFactsArray by lazy { context.resources.getStringArray(R.array.local_cat_facts) } + private val localFactsSize by lazy { localFactsArray.size } + /** - * Реализуйте функцию otus.homework.reactivecats.LocalCatFactsGenerator#generateCatFact так, - * чтобы она возвращала Fact со случайной строкой из массива строк R.array.local_cat_facts + * Реализуйте функцию [otus.homework.reactivecats.LocalCatFactsGenerator.generateCatFact] так, + * чтобы она возвращала Fact со случайной строкой из массива строк R.array.local_cat_facts * обернутую в подходящий стрим(Flowable/Single/Observable и т.п) */ - fun generateCatFact(): Single { - return Single.never() + private fun generateCatFact() = Single.fromCallable { + Fact(localFactsArray[Random.nextInt(localFactsSize)]) } /** - * Реализуйте функцию otus.homework.reactivecats.LocalCatFactsGenerator#generateCatFactPeriodically так, + * Реализуйте функцию [otus.homework.reactivecats.LocalCatFactsGenerator.generateCatFactPeriodically] так, * чтобы она эмитила Fact со случайной строкой из массива строк R.array.local_cat_facts каждые 2000 миллисекунд. * Если вновь заэмиченный Fact совпадает с предыдущим - пропускаем элемент. */ - fun generateCatFactPeriodically(): Flowable { - val success = Fact(context.resources.getStringArray(R.array.local_cat_facts)[Random.nextInt(5)]) - return Flowable.empty() - } + fun generateCatFactPeriodically(): Flowable = + Flowable.interval(2000, TimeUnit.MILLISECONDS) + .flatMap { generateCatFact().toFlowable() } + .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..7e2c6d27 100644 --- a/app/src/main/java/otus/homework/reactivecats/MainActivity.kt +++ b/app/src/main/java/otus/homework/reactivecats/MainActivity.kt @@ -1,10 +1,9 @@ package otus.homework.reactivecats -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import androidx.activity.viewModels -import androidx.lifecycle.lifecycleScope +import androidx.appcompat.app.AppCompatActivity import com.google.android.material.snackbar.Snackbar class MainActivity : AppCompatActivity() { @@ -14,7 +13,6 @@ class MainActivity : AppCompatActivity() { CatsViewModelFactory( diContainer.service, diContainer.localCatFactsGenerator(applicationContext), - applicationContext ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 46c95785..4c0dd79c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,7 @@ okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-i picasso = { module = "com.squareup.picasso:picasso", version.ref = "picasso" } retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" } +retrofit-rxjava= { group = "com.squareup.retrofit2", name = "adapter-rxjava2", version.ref = "retrofit" } rxandroid = { module = "io.reactivex.rxjava2:rxandroid", version.ref = "rxandroid" } rxjava = { module = "io.reactivex.rxjava2:rxjava", version.ref = "rxjava" }