diff --git a/app/build.gradle b/app/build.gradle index 71df92d..9c92715 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,4 +46,5 @@ dependencies { 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' -} \ No newline at end of file + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' +} diff --git a/app/src/main/java/otus/homework/reactivecats/CatsService.kt b/app/src/main/java/otus/homework/reactivecats/CatsService.kt index c79be48..d6289a2 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsService.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsService.kt @@ -1,10 +1,11 @@ package otus.homework.reactivecats -import retrofit2.Call +import io.reactivex.Single +import retrofit2.Response import retrofit2.http.GET interface CatsService { @GET("random?animal_type=cat") - fun getCatFact(): Call -} \ No newline at end of file + fun getCatFact(): Single> +} diff --git a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt index d62eaf9..4acd486 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt @@ -5,40 +5,92 @@ 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.Observable +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import java.lang.RuntimeException +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 + private val compositeDisposable = CompositeDisposable() + private val defaultErrorText = context.getString(R.string.default_error_text) + init { - catsService.getCatFact().enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { + catsService.getCatFact() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .map { response -> if (response.isSuccessful && response.body() != null) { - _catsLiveData.value = Success(response.body()!!) + Success(response.body()!!) } else { - _catsLiveData.value = Error( - response.errorBody()?.string() ?: context.getString( - R.string.default_error_text - ) - ) + Error(response.errorBody()?.string() ?: defaultErrorText) } } + .addSubscribe( + { _catsLiveData.value = it }, + { _catsLiveData.value = ServerError } + ) + } - override fun onFailure(call: Call, t: Throwable) { - _catsLiveData.value = ServerError + fun getFacts() { + Observable.interval(0, 2, TimeUnit.SECONDS) + .subscribeOn(Schedulers.computation()) + .flatMapSingle { catsService.getCatFact() } + .map { response -> + if (response.isSuccessful && response.body() != null) { + response.body()!! + } else { + throw RuntimeException("Wrong response: ${response.errorBody()?.string()}") + } } - }) + .onErrorResumeNext( + localCatFactsGenerator.generateCatFactPeriodically().toObservable() + ) + .observeOn(AndroidSchedulers.mainThread()) + .addSubscribe( + { _catsLiveData.value = Success(it) }, + { _catsLiveData.value = ServerError } + ) } - fun getFacts() {} + override fun onCleared() { + compositeDisposable.dispose() + super.onCleared() + } + + private fun Observable.addSubscribe( + onSuccess: (T) -> Unit, + onError: (Throwable) -> Unit + ) { + compositeDisposable.add( + this.subscribe( + { onSuccess.invoke(it) }, + { onError.invoke(it) } + ) + ) + } + + private fun Single.addSubscribe( + onSuccess: (T) -> Unit, + onError: (Throwable) -> Unit + ) { + compositeDisposable.add( + this.subscribe( + { onSuccess.invoke(it) }, + { onError.invoke(it) } + ) + ) + } } class CatsViewModelFactory( @@ -55,4 +107,4 @@ class CatsViewModelFactory( sealed class Result data class Success(val fact: Fact) : Result() data class Error(val message: String) : Result() -object ServerError : Result() \ No newline at end of file +object ServerError : Result() diff --git a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt index dfbb9a2..31ef2f6 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 { @@ -9,6 +10,7 @@ class DiContainer { private val retrofit by lazy { Retrofit.Builder() .baseUrl("https://cat-fact.herokuapp.com/facts/") + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build() } @@ -16,4 +18,4 @@ class DiContainer { val service 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 4481062..3201468 100644 --- a/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt +++ b/app/src/main/java/otus/homework/reactivecats/LocalCatFactsGenerator.kt @@ -3,19 +3,29 @@ 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 + context: Context ) { + private val random = java.util.Random() + private val array = context.resources.getStringArray(R.array.local_cat_facts) + + private val catFactFlowable by lazy { + Flowable.interval(0,2000, TimeUnit.MILLISECONDS) + .map { getRandomFact() } + .distinctUntilChanged() + } + /** * Реализуйте функцию otus.homework.reactivecats.LocalCatFactsGenerator#generateCatFact так, * чтобы она возвращала Fact со случайной строкой из массива строк R.array.local_cat_facts * обернутую в подходящий стрим(Flowable/Single/Observable и т.п) */ fun generateCatFact(): Single { - return Single.never() + return Single.just(getRandomFact()) } /** @@ -24,7 +34,14 @@ class LocalCatFactsGenerator( * Если вновь заэмиченный Fact совпадает с предыдущим - пропускаем элемент. */ fun generateCatFactPeriodically(): Flowable { - val success = Fact(context.resources.getStringArray(R.array.local_cat_facts)[Random.nextInt(5)]) - return Flowable.empty() + return catFactFlowable + } + + private fun getRandomFact(): Fact { + return Fact(getRandomString()) + } + + private fun getRandomString(): String { + return array[random.nextInt(array.size - 1)] } -} \ 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 8ec9571..1ad6ef9 100644 --- a/app/src/main/java/otus/homework/reactivecats/MainActivity.kt +++ b/app/src/main/java/otus/homework/reactivecats/MainActivity.kt @@ -29,5 +29,6 @@ class MainActivity : AppCompatActivity() { ServerError -> Snackbar.make(view, "Network error", 1000).show() } } + catsViewModel.getFacts() } -} \ No newline at end of file +}