From 39851150782ec2a1b9a969508323f3ebfd80aa5c Mon Sep 17 00:00:00 2001 From: antonkazakov Date: Wed, 8 May 2024 22:32:40 +0400 Subject: [PATCH 1/2] updated infrastructure --- flowcats/build.gradle | 9 ++-- flowcats/src/main/AndroidManifest.xml | 3 +- .../otus/homework/flowcats/CatsViewModel.kt | 26 +++++++--- .../main/java/otus/homework/flowcats/Fact.kt | 52 ++++++++++++------- .../otus/homework/flowcats/MainActivity.kt | 31 +++++++++-- 5 files changed, 87 insertions(+), 34 deletions(-) diff --git a/flowcats/build.gradle b/flowcats/build.gradle index 0ea35e68..116eba4a 100644 --- a/flowcats/build.gradle +++ b/flowcats/build.gradle @@ -4,15 +4,17 @@ plugins { } android { - compileSdkVersion 30 - buildToolsVersion "30.0.3" + compileSdkVersion 31 + buildToolsVersion "31.0.1" + + namespace = "otus.homework.flowcats" namespace = "otus.homework.flowcats" defaultConfig { applicationId "otus.homework.flowcats" minSdkVersion 23 - targetSdkVersion 30 + targetSdkVersion 31 versionCode 1 versionName "1.0" @@ -48,4 +50,5 @@ dependencies { implementation 'androidx.activity:activity-ktx:1.2.3' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.3' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' } \ No newline at end of file diff --git a/flowcats/src/main/AndroidManifest.xml b/flowcats/src/main/AndroidManifest.xml index 2deb6454..77503dbb 100644 --- a/flowcats/src/main/AndroidManifest.xml +++ b/flowcats/src/main/AndroidManifest.xml @@ -10,7 +10,8 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Flow" > - + diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index 0d8ba8a7..ef58eed4 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -1,7 +1,11 @@ package otus.homework.flowcats import androidx.lifecycle.* +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -10,14 +14,16 @@ class CatsViewModel( private val catsRepository: CatsRepository ) : ViewModel() { - private val _catsLiveData = MutableLiveData() - val catsLiveData: LiveData = _catsLiveData - + private val _catsStateFlow: MutableStateFlow = MutableStateFlow(Success(Fact.NONE)) + val catsStateFlow: StateFlow = _catsStateFlow.asStateFlow() + private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + _catsStateFlow.value = Error(throwable.message ?: throwable.toString()) + } init { - viewModelScope.launch { - withContext(Dispatchers.IO) { + viewModelScope.launch ( exceptionHandler){ + withContext(Dispatchers.IO ) { catsRepository.listenForCatFacts().collect { - _catsLiveData.value = it + _catsStateFlow.value = Success(it) } } } @@ -26,6 +32,10 @@ class CatsViewModel( class CatsViewModelFactory(private val catsRepository: CatsRepository) : ViewModelProvider.NewInstanceFactory() { - override fun create(modelClass: Class): T = + override fun create(modelClass: Class): T = CatsViewModel(catsRepository) as T -} \ No newline at end of file +} + +sealed class Result +data class Success(val fact: Fact) : Result() +data class Error(val message: String) : Result() \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt index 602303eb..f0269aca 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt @@ -3,22 +3,36 @@ package otus.homework.flowcats import com.google.gson.annotations.SerializedName data class Fact( - @field:SerializedName("createdAt") - val createdAt: String, - @field:SerializedName("deleted") - val deleted: Boolean, - @field:SerializedName("_id") - val id: String, - @field:SerializedName("text") - val text: String, - @field:SerializedName("source") - val source: String, - @field:SerializedName("used") - val used: Boolean, - @field:SerializedName("type") - val type: String, - @field:SerializedName("user") - val user: String, - @field:SerializedName("updatedAt") - val updatedAt: String -) \ No newline at end of file + @field:SerializedName("createdAt") + val createdAt: String, + @field:SerializedName("deleted") + val deleted: Boolean, + @field:SerializedName("_id") + val id: String, + @field:SerializedName("text") + val text: String, + @field:SerializedName("source") + val source: String, + @field:SerializedName("used") + val used: Boolean, + @field:SerializedName("type") + val type: String, + @field:SerializedName("user") + val user: String, + @field:SerializedName("updatedAt") + val updatedAt: String +) { + companion object { + val NONE = Fact( + "", + false, + "", + "", + "", + false, + "", + "", + "" + ) + } +} \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt index edea434b..9853c4c1 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt @@ -1,8 +1,16 @@ package otus.homework.flowcats -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.widget.Toast import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { @@ -14,8 +22,25 @@ class MainActivity : AppCompatActivity() { val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView setContentView(view) - catsViewModel.catsLiveData.observe(this){ - view.populate(it) + observeFlow(this, catsViewModel.catsStateFlow, view) + } + + private fun observeFlow(lifecycleOwner: LifecycleOwner, state: StateFlow, view: CatsView) { + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + state.collect { state -> + when (state) { + is Error -> Toast.makeText( + this@MainActivity, + state.message, Toast.LENGTH_LONG + ).show() + + is Success -> { + view.populate(state.fact) + } + } + } + } } } } \ No newline at end of file From 151f7923ccf1507ea64a5326e8f91d002505cbbc Mon Sep 17 00:00:00 2001 From: Bogdan Patseev Date: Mon, 26 May 2025 22:13:52 +0300 Subject: [PATCH 2/2] solve tasks --- .../otus/homework/flow/SampleInteractor.kt | 59 +++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index 1993c064..fac8a1d9 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -1,6 +1,7 @@ package otus.homework.flow import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.* @ExperimentalCoroutinesApi @@ -18,7 +19,13 @@ class SampleInteractor( * 6) возвращает результат */ fun task1(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .map { it * 5 } + .filter { it > 20 } + .filter { it % 2 != 0 } + .map { "$it won" } + .take(3) + } /** @@ -28,8 +35,39 @@ class SampleInteractor( * Если входное число делится на 15 - эмитим само число и после него эмитим строку FizzBuzz * Если число не делится на 3,5,15 - эмитим само число */ + @OptIn(FlowPreview::class) fun task2(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .flatMapConcat { + when { + it % 15 == 0 -> { + flow{ + emit(it.toString()) + emit("FizzBuzz") + } + } + + it % 5 == 0 -> { + flow{ + emit(it.toString()) + emit("Buzz") + } + } + + it % 3 == 0 -> { + flow{ + emit(it.toString()) + emit("Fizz") + } + } + + else -> { + flow { + emit(it.toString()) + } + } + } + } } /** @@ -38,7 +76,10 @@ class SampleInteractor( * Если айтемы в одно из флоу кончились то результирующий флоу также должен закончится */ fun task3(): Flow> { - return flowOf() + return sampleRepository.produceColors() + .zip(sampleRepository.produceForms()){ color, form -> + color to form + } } /** @@ -48,6 +89,16 @@ class SampleInteractor( * При любом исходе, будь то выброс исключения или успешная отработка функции вызовите метод dotsRepository.completed() */ fun task4(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .catch {throwable -> + if (throwable is IllegalArgumentException) { + emit(-1) + } else { + throw throwable + } + } + .onCompletion { + sampleRepository.completed() + } } } \ No newline at end of file