diff --git a/app/build.gradle b/app/build.gradle index 71df92dd..17ffe904 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { namespace "otus.homework.reactivecats" defaultConfig { applicationId "otus.homework.reactivecats" - minSdkVersion 23 + minSdkVersion 24 targetSdkVersion 34 versionCode 1 @@ -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' + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.11.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a6244518..c4f4ab3c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" + android:networkSecurityConfig="@xml/network_security_config" android:theme="@style/Theme.ReactiveCats"> diff --git a/app/src/main/java/otus/homework/reactivecats/CatsService.kt b/app/src/main/java/otus/homework/reactivecats/CatsService.kt index c79be483..a201631c 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 + @GET("fact") + 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..ce18cb2f 100644 --- a/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt +++ b/app/src/main/java/otus/homework/reactivecats/CatsViewModel.kt @@ -5,40 +5,70 @@ 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.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 + 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 - } - }) + disposable.add( + catsService.getCatFact() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + _catsLiveData.value = Success(it) + }, + { + _catsLiveData.value = Error(message = it.message ?: "Some error") + } + ) + ) + + disposable.add( + localCatFactsGenerator.generateCatFactPeriodically() + .subscribe({ + println("Fact = $it\n") + }) + ) + + getFacts() } - fun getFacts() {} + fun getFacts() { + disposable.add( + Observable.interval(2, TimeUnit.SECONDS).doOnNext { + //скорее всего есть какой-то более подходящий вариант, + // поскольку текущая реализация не выглядит "элегантной" + disposable.add( + catsService.getCatFact() + .onErrorResumeNext(localCatFactsGenerator.generateCatFact()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + _catsLiveData.value = Success(it) + }, { + _catsLiveData.value = Error(message = it.message ?: "Some error") + }) + ) + }.subscribe() + ) + } + + override fun onCleared() { + disposable.dispose() + } } 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 dfbb9a2b..f5c8f1f7 100644 --- a/app/src/main/java/otus/homework/reactivecats/DiContainer.kt +++ b/app/src/main/java/otus/homework/reactivecats/DiContainer.kt @@ -2,14 +2,16 @@ package otus.homework.reactivecats import android.content.Context import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory class DiContainer { private val retrofit by lazy { Retrofit.Builder() - .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/Fact.kt b/app/src/main/java/otus/homework/reactivecats/Fact.kt index c32f5847..94f36d52 100644 --- a/app/src/main/java/otus/homework/reactivecats/Fact.kt +++ b/app/src/main/java/otus/homework/reactivecats/Fact.kt @@ -3,6 +3,6 @@ package otus.homework.reactivecats import com.google.gson.annotations.SerializedName data class Fact( - @field:SerializedName("text") + @field:SerializedName("fact") val text: String ) \ 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..67e03000 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,7 @@ class LocalCatFactsGenerator( * обернутую в подходящий стрим(Flowable/Single/Observable и т.п) */ fun generateCatFact(): Single { - return Single.never() + return Single.just(getRandomFact()) } /** @@ -24,7 +25,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 Flowable.interval(2, TimeUnit.SECONDS) + .map { + getRandomFact() + }.distinctUntilChanged() + } + + private fun getRandomFact(): Fact { + val facts = context.resources.getStringArray(R.array.local_cat_facts) + return Fact(facts[Random.nextInt(facts.size)]) } } \ No newline at end of file diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..2e8fae1b --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file