From 02e49faeda485d02566c90c3b4fcc912c65a35d2 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 12:34:04 +0300 Subject: [PATCH 1/8] add updateTime --- .../ui/timer/TimerFragment.kt | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt index 1b7c0f1..534b5e2 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt @@ -6,12 +6,12 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import ru.otus.coroutineshomework.databinding.FragmentTimerBinding import java.util.Locale +import java.util.Timer +import kotlin.concurrent.schedule import kotlin.properties.Delegates import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds @@ -33,6 +33,7 @@ class TimerFragment : Fragment() { stopTimer() } } + private var timeTicker: Timer? = null private fun setButtonsState(started: Boolean) { with(binding) { @@ -75,11 +76,21 @@ class TimerFragment : Fragment() { } private fun startTimer() { - // TODO: Start timer + timeTicker = Timer() + + timeTicker?.schedule(0L, 100L) { + updateTime() + } + } + + private fun updateTime() { + this.lifecycleScope.launch(Dispatchers.Main) { + time = time.plus(1.milliseconds) + } } private fun stopTimer() { - // TODO: Stop timer + timeTicker?.cancel() } override fun onDestroyView() { From b1657eb434ea2338fef13a35273b0901ff7cefd9 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 12:35:35 +0300 Subject: [PATCH 2/8] 1 task is done --- .../kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt index 534b5e2..3ced8ce 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt @@ -77,7 +77,6 @@ class TimerFragment : Fragment() { private fun startTimer() { timeTicker = Timer() - timeTicker?.schedule(0L, 100L) { updateTime() } From a003f539d098b524f9ab4a99d5942653820d36b9 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 13:18:02 +0300 Subject: [PATCH 3/8] 1.2 task is done --- .../ui/timer/TimerFragment.kt | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt index 3ced8ce..c9c28fd 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt @@ -7,6 +7,8 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import ru.otus.coroutineshomework.databinding.FragmentTimerBinding import java.util.Locale @@ -21,9 +23,7 @@ class TimerFragment : Fragment() { private var _binding: FragmentTimerBinding? = null private val binding get() = _binding!! - private var time: Duration by Delegates.observable(Duration.ZERO) { _, _, newValue -> - binding.time.text = newValue.toDisplayString() - } + private var timeFlow: MutableStateFlow = MutableStateFlow(0.milliseconds) private var started by Delegates.observable(false) { _, _, newValue -> setButtonsState(newValue) @@ -54,12 +54,18 @@ class TimerFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) savedInstanceState?.let { - time = it.getLong(TIME).milliseconds + timeFlow.value = it.getLong(TIME).milliseconds started = it.getBoolean(STARTED) } + setButtonsState(started) with(binding) { - time.text = this@TimerFragment.time.toDisplayString() + lifecycleScope.launch { + timeFlow.collect { + time.text = it.toDisplayString() + } + } + btnStart.setOnClickListener { started = true } @@ -71,7 +77,7 @@ class TimerFragment : Fragment() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putLong(TIME, time.inWholeMilliseconds) + outState.putLong(TIME, timeFlow.value.inWholeMilliseconds) outState.putBoolean(STARTED, started) } @@ -84,7 +90,7 @@ class TimerFragment : Fragment() { private fun updateTime() { this.lifecycleScope.launch(Dispatchers.Main) { - time = time.plus(1.milliseconds) + timeFlow.value = timeFlow.value.plus(1.milliseconds) } } From 3b82876f59d9504a1303f9b6986187e23a469cea Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 13:20:00 +0300 Subject: [PATCH 4/8] 1.2 task is done fix --- .../ru/otus/coroutineshomework/ui/timer/TimerFragment.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt index c9c28fd..f36cc18 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/timer/TimerFragment.kt @@ -8,7 +8,6 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import ru.otus.coroutineshomework.databinding.FragmentTimerBinding import java.util.Locale @@ -89,9 +88,7 @@ class TimerFragment : Fragment() { } private fun updateTime() { - this.lifecycleScope.launch(Dispatchers.Main) { - timeFlow.value = timeFlow.value.plus(1.milliseconds) - } + timeFlow.value = timeFlow.value.plus(1.milliseconds) } private fun stopTimer() { From 4fc9e9f8df0650580f5e0a0e209e2d4007e5be54 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 14:20:45 +0300 Subject: [PATCH 5/8] 2 task is done --- .../ui/login/LoginViewModel.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt index 5fae38a..28c9afd 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt @@ -3,11 +3,17 @@ package ru.otus.coroutineshomework.ui.login import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import ru.otus.coroutineshomework.ui.login.data.Credentials +import ru.otus.coroutineshomework.ui.login.data.User class LoginViewModel : ViewModel() { private val _state = MutableLiveData(LoginViewState.Login()) val state: LiveData = _state + private val loginAIp = LoginApi() /** * Login to the network @@ -15,13 +21,27 @@ class LoginViewModel : ViewModel() { * @param password user password */ fun login(name: String, password: String) { - // TODO: Implement login + + viewModelScope.launch(Dispatchers.IO) { + _state.postValue(LoginViewState.LoggingIn) + + try { + val userNetworkRequest = loginAIp.login(Credentials(name, password)) + _state.postValue(LoginViewState.Content(userNetworkRequest)) + } catch (e: Exception) { + _state.postValue(LoginViewState.Login(e)) + } + } } /** * Logout from the network */ fun logout() { - // TODO: Implement logout + viewModelScope.launch(Dispatchers.IO) { + _state.postValue(LoginViewState.LoggingOut) + loginAIp.logout() + _state.postValue(LoginViewState.Login()) + } } } From 5a8e128c0eb55203620be22fc479f09e4d33c5d5 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 14:46:31 +0300 Subject: [PATCH 6/8] 2.2 task is done in a simple way --- .../ui/login/LoginFragment.kt | 18 +++++++++++------- .../ui/login/LoginViewModel.kt | 16 +++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginFragment.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginFragment.kt index 06c3afe..b901783 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginFragment.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginFragment.kt @@ -7,6 +7,9 @@ import android.view.ViewGroup import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch import ru.otus.coroutineshomework.databinding.ContentBinding import ru.otus.coroutineshomework.databinding.FragmentLoginBinding import ru.otus.coroutineshomework.databinding.LoadingBinding @@ -42,13 +45,14 @@ class LoginFragment : Fragment() { setupLogin() setupContent() - - loginViewModel.state.observe(viewLifecycleOwner) { - when(it) { - is LoginViewState.Login -> showLogin(it) - LoginViewState.LoggingIn -> showLoggingIn() - is LoginViewState.Content -> showContent(it) - LoginViewState.LoggingOut -> showLoggingOut() + lifecycleScope.launch { + loginViewModel.state.collect() { + when (it) { + is LoginViewState.Login -> showLogin(it) + LoginViewState.LoggingIn -> showLoggingIn() + is LoginViewState.Content -> showContent(it) + LoginViewState.LoggingOut -> showLoggingOut() + } } } } diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt index 28c9afd..15efeb8 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/login/LoginViewModel.kt @@ -5,14 +5,16 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import ru.otus.coroutineshomework.ui.login.data.Credentials import ru.otus.coroutineshomework.ui.login.data.User class LoginViewModel : ViewModel() { - private val _state = MutableLiveData(LoginViewState.Login()) - val state: LiveData = _state + private val _state = MutableStateFlow(LoginViewState.Login()) + val state: StateFlow = _state private val loginAIp = LoginApi() /** @@ -23,13 +25,13 @@ class LoginViewModel : ViewModel() { fun login(name: String, password: String) { viewModelScope.launch(Dispatchers.IO) { - _state.postValue(LoginViewState.LoggingIn) + _state.value = LoginViewState.LoggingIn try { val userNetworkRequest = loginAIp.login(Credentials(name, password)) - _state.postValue(LoginViewState.Content(userNetworkRequest)) + _state.value = LoginViewState.Content(userNetworkRequest) } catch (e: Exception) { - _state.postValue(LoginViewState.Login(e)) + _state.value = LoginViewState.Login(e) } } } @@ -39,9 +41,9 @@ class LoginViewModel : ViewModel() { */ fun logout() { viewModelScope.launch(Dispatchers.IO) { - _state.postValue(LoginViewState.LoggingOut) + _state.value = LoginViewState.LoggingOut loginAIp.logout() - _state.postValue(LoginViewState.Login()) + _state.value = LoginViewState.Login() } } } From 8e08fc0d51d3590cb91a0990b039483fb7b18482 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Sun, 26 Jan 2025 15:23:07 +0300 Subject: [PATCH 7/8] 3 task is done --- .../ui/network/NetworkViewModel.kt | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt index f006e03..a94c168 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt @@ -4,8 +4,10 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlin.random.Random @@ -18,7 +20,27 @@ class NetworkViewModel : ViewModel() { val result: LiveData = _result fun startTest(numberOfThreads: Int) { - // TODO: Implement the logic + val results: MutableList = mutableListOf(0L) + _result.postValue(results.first()) + + viewModelScope.launch { + _running.postValue(true) + repeat(numberOfThreads) { + try { + val timeTask = emulateBlockingNetworkRequest() + + timeTask.getOrNull()?.let { + if (it > 0) { + results.add(it) + } + } + } catch (_: Throwable) { + } + } + _running.postValue(false) + val middleValue = results.average().toLong() + _result.postValue(middleValue) + } } private companion object { From 845f1fc96bb694f5b4c44a05f55a0d3b4cf9d7b5 Mon Sep 17 00:00:00 2001 From: SpiritualAdviser Date: Mon, 27 Jan 2025 18:50:25 +0300 Subject: [PATCH 8/8] 3 task is fix to awaitAll --- .../ui/network/NetworkViewModel.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt index a94c168..7f5cce5 100644 --- a/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt +++ b/app/src/main/kotlin/ru/otus/coroutineshomework/ui/network/NetworkViewModel.kt @@ -5,9 +5,16 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.selects.SelectClause1 import kotlinx.coroutines.withContext import kotlin.random.Random @@ -20,25 +27,19 @@ class NetworkViewModel : ViewModel() { val result: LiveData = _result fun startTest(numberOfThreads: Int) { - val results: MutableList = mutableListOf(0L) - _result.postValue(results.first()) + _result.postValue(0L) + val deferredList = ArrayList>>() viewModelScope.launch { _running.postValue(true) - repeat(numberOfThreads) { - try { - val timeTask = emulateBlockingNetworkRequest() - timeTask.getOrNull()?.let { - if (it > 0) { - results.add(it) - } - } - } catch (_: Throwable) { - } + repeat(numberOfThreads) { + deferredList.add(async { emulateBlockingNetworkRequest() }) } + val middleValue = + deferredList.awaitAll().mapNotNull { it.getOrNull() }.average().toLong() + _running.postValue(false) - val middleValue = results.average().toLong() _result.postValue(middleValue) } }