From 60dc635a9bb66704217493b1beabab381524953b Mon Sep 17 00:00:00 2001 From: PabloK Date: Sat, 17 Feb 2024 19:31:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=B7=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE,=20=D0=B5=D1=81=D1=82=D1=8C=202=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 + .../otus/homework/reactivecats/CatsService.kt | 4 +- .../homework/reactivecats/CatsViewModel.kt | 74 +++++++++++++------ .../otus/homework/reactivecats/DiContainer.kt | 2 + .../reactivecats/LocalCatFactsGenerator.kt | 20 +++-- .../homework/reactivecats/MainActivity.kt | 8 +- 6 files changed, 82 insertions(+), 30 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 71df92dd..ea5b71e7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,6 +44,10 @@ dependencies { implementation 'com.squareup.picasso:picasso:2.71828' implementation 'androidx.activity:activity-ktx:1.8.2' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0' + implementation "io.reactivex.rxjava2:rxjava:2.2.21" implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + + // Для использования RxJava c Retrofit + implementation "com.squareup.retrofit2:adapter-rxjava2:2.7.1" } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/reactivecats/CatsService.kt b/app/src/main/java/otus/homework/reactivecats/CatsService.kt index c79be483..17d1e38e 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsService.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsService.kt @@ -1,10 +1,10 @@ package otus.homework.reactivecats -import retrofit2.Call +import io.reactivex.Single import retrofit2.http.GET interface CatsService { @GET("random?animal_type=cat") - 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..a74fd9e6 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt @@ -5,48 +5,80 @@ 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.BackpressureStrategy +import io.reactivex.Flowable +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import java.util.concurrent.TimeUnit class CatsViewModel( - catsService: CatsService, - localCatFactsGenerator: LocalCatFactsGenerator, + private val catsService: CatsService, + private val localCatFactsGenerator: LocalCatFactsGenerator, context: Context ) : ViewModel() { private val _catsLiveData = MutableLiveData() val catsLiveData: LiveData = _catsLiveData + 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 - ) - ) + val disposable = getFacts1() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { fact -> + println("mytag: +++ fact received") + _catsLiveData.value = Success(fact) + }, + { throwable -> + _catsLiveData.value = Error(throwable?.message?:context.getString(R.string.default_error_text)) } + ) + compositeDisposable.add(disposable) + } + + //Вопрос: при медленном интернет соединении посылается первый запрос, потом пауза в 6-10 сек, + // а потом выплевывает сразу несколько значений. Как сделать так, чтоб поток ждал ответа от сервера? + fun getFacts(): Observable { + val source = Observable.interval(2, TimeUnit.SECONDS) + .flatMap { + println("mytag: sending request") + catsService.getCatFact().toObservable() } + .onErrorResumeNext( + localCatFactsGenerator.generateCatFactPeriodically() + ) - override fun onFailure(call: Call, t: Throwable) { - _catsLiveData.value = ServerError + return source + } + + fun getFacts1(): Flowable { + // Вопрос: почему при создании interval не просить указать BackpressureStrategy? + val source = Flowable.interval(2, TimeUnit.SECONDS) + .flatMap { + println("mytag: sending request") + catsService.getCatFact().toFlowable() } - }) + .onErrorResumeNext( + localCatFactsGenerator.generateCatFactPeriodically().toFlowable(BackpressureStrategy.BUFFER) + ) + + return source } - fun getFacts() {} + fun onStop() { + compositeDisposable.dispose() + } } class CatsViewModelFactory( private val catsRepository: CatsService, private val localCatFactsGenerator: LocalCatFactsGenerator, private val context: Context -) : - ViewModelProvider.NewInstanceFactory() { +) : ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T = CatsViewModel(catsRepository, localCatFactsGenerator, context) as T diff --git a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt index dfbb9a2b..ad1aa751 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 { @@ -10,6 +11,7 @@ class DiContainer { Retrofit.Builder() .baseUrl("https://cat-fact.herokuapp.com/facts/") .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..146cdade 100644 --- a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt +++ b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt @@ -1,8 +1,9 @@ package otus.homework.reactivecats import android.content.Context -import io.reactivex.Flowable +import io.reactivex.Observable import io.reactivex.Single +import java.util.concurrent.TimeUnit import kotlin.random.Random class LocalCatFactsGenerator( @@ -15,7 +16,10 @@ class LocalCatFactsGenerator( * обернутую в подходящий стрим(Flowable/Single/Observable и т.п) */ fun generateCatFact(): Single { - return Single.never() + return Single.create { + val fact = Fact(context.resources.getStringArray(R.array.local_cat_facts)[Random.nextInt(5)]) + it.onSuccess(fact) + } } /** @@ -23,8 +27,14 @@ class LocalCatFactsGenerator( * чтобы она эмитила 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(): Observable { + val source = Observable.interval(2, TimeUnit.SECONDS) + .map { + val fact = Fact(context.resources.getStringArray(R.array.local_cat_facts)[Random.nextInt(5)]) + fact + } + .distinctUntilChanged() + + return source } } \ 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..44bc7f38 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() { @@ -30,4 +29,9 @@ class MainActivity : AppCompatActivity() { } } } + + override fun onStop() { + super.onStop() + catsViewModel.onStop() + } } \ No newline at end of file