diff --git a/flowcats/build.gradle b/flowcats/build.gradle index 0ea35e68..22eb3ef8 100644 --- a/flowcats/build.gradle +++ b/flowcats/build.gradle @@ -4,7 +4,7 @@ plugins { } android { - compileSdkVersion 30 + compileSdkVersion 33 buildToolsVersion "30.0.3" namespace = "otus.homework.flowcats" @@ -12,7 +12,7 @@ android { defaultConfig { applicationId "otus.homework.flowcats" minSdkVersion 23 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 1 versionName "1.0" @@ -48,4 +48,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.0' } \ No newline at end of file diff --git a/flowcats/src/main/AndroidManifest.xml b/flowcats/src/main/AndroidManifest.xml index 2deb6454..d57e0372 100644 --- a/flowcats/src/main/AndroidManifest.xml +++ b/flowcats/src/main/AndroidManifest.xml @@ -10,7 +10,9 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Flow" > - + diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt index 10fcb77d..b8ce9eb9 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt @@ -1,7 +1,10 @@ package otus.homework.flowcats +import android.util.Log +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn class CatsRepository( private val catsService: CatsService, @@ -10,9 +13,14 @@ class CatsRepository( fun listenForCatFacts() = flow { while (true) { - val latestNews = catsService.getCatFact() - emit(latestNews) + Log.d("TAGTAG", "listenForCatFacts: ") + try { + val latestNews = catsService.getCatFact() + emit(Result.Success(latestNews)) + } catch (t: Throwable) { + emit(Result.Error(t)) + } delay(refreshIntervalMs) } - } + }.flowOn(Dispatchers.IO) } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt index 6a195f3a..63617e33 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt @@ -3,6 +3,7 @@ package otus.homework.flowcats import android.content.Context import android.util.AttributeSet import android.widget.TextView +import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout class CatsView @JvmOverloads constructor( @@ -11,12 +12,16 @@ class CatsView @JvmOverloads constructor( defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView { - override fun populate(fact: Fact) { - findViewById(R.id.fact_textView).text = fact.text + override fun populate(text: String) { + findViewById(R.id.fact_textView).text = text + } + + fun showToast(text: String) { + Toast.makeText(context, text, Toast.LENGTH_SHORT).show() } } interface ICatsView { - fun populate(fact: Fact) + fun populate(text: String) } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index 0d8ba8a7..226dfa3d 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -1,23 +1,28 @@ package otus.homework.flowcats import androidx.lifecycle.* -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 class CatsViewModel( private val catsRepository: CatsRepository ) : ViewModel() { - private val _catsLiveData = MutableLiveData() - val catsLiveData: LiveData = _catsLiveData + private val _state: MutableStateFlow = MutableStateFlow(State.Initial) + val state: StateFlow = _state.asStateFlow() init { viewModelScope.launch { - withContext(Dispatchers.IO) { - catsRepository.listenForCatFacts().collect { - _catsLiveData.value = it + catsRepository.listenForCatFacts().collect { + when (it) { + is Result.Success<*> -> (it.data as? Fact)?.let { fact -> + _state.emit(State.Success(fact.text)) + } + + is Result.Error -> _state.emit(State.Error(it.t.message ?: "")) } } } @@ -26,6 +31,6 @@ 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 diff --git a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt index edea434b..470c96aa 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt @@ -3,6 +3,11 @@ package otus.homework.flowcats import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.activity.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { @@ -13,9 +18,16 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView setContentView(view) - - catsViewModel.catsLiveData.observe(this){ - view.populate(it) + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + catsViewModel.state.collect { + when (it) { + State.Initial -> Unit + is State.Error -> view.showToast(it.text) + is State.Success -> view.populate(it.text) + } + } + } } } } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/Result.kt b/flowcats/src/main/java/otus/homework/flowcats/Result.kt new file mode 100644 index 00000000..df72da28 --- /dev/null +++ b/flowcats/src/main/java/otus/homework/flowcats/Result.kt @@ -0,0 +1,7 @@ +package otus.homework.flowcats + + +sealed class Result { + data class Success(val data: T) : Result() + data class Error(val t: Throwable) : Result() +} \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/State.kt b/flowcats/src/main/java/otus/homework/flowcats/State.kt new file mode 100644 index 00000000..520ddd29 --- /dev/null +++ b/flowcats/src/main/java/otus/homework/flowcats/State.kt @@ -0,0 +1,7 @@ +package otus.homework.flowcats + +sealed class State { + data object Initial : State() + data class Success(val text: String) : State() + data class Error(val text: String) : State() +} \ No newline at end of file diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index 1993c064..349c3a46 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,12 @@ 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) } /** @@ -29,7 +35,15 @@ class SampleInteractor( * Если число не делится на 3,5,15 - эмитим само число */ fun task2(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .flatMapConcat { + when { + it % 15 == 0 -> flowOf(it.toString(), "FizzBuzz") + it % 3 == 0 -> flowOf(it.toString(), "Fizz") + it % 5 == 0 -> flowOf(it.toString(), "Buzz") + else -> flowOf(it.toString()) + } + } } /** @@ -38,7 +52,12 @@ class SampleInteractor( * Если айтемы в одно из флоу кончились то результирующий флоу также должен закончится */ fun task3(): Flow> { - return flowOf() + val flow1 = sampleRepository.produceColors() + val flow2 = sampleRepository.produceForms() + + return flow1.zip(flow2) { first, second -> + Pair(first, second) + } } /** @@ -48,6 +67,14 @@ class SampleInteractor( * При любом исходе, будь то выброс исключения или успешная отработка функции вызовите метод dotsRepository.completed() */ fun task4(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .catch { e -> + if (e is IllegalArgumentException) { + println(e.toString()) + emit(-1) + } else { + throw e + } + }.onCompletion { sampleRepository.completed() } } } \ No newline at end of file