Tran Thang
02/22/2023, 12:47 PMclass MovieRepositoryImpl(private val api: MovieApi):MovieRepository {
override suspend fun fetchMovie(): Movie {
return api.fetchMovie()
}
override suspend fun fetchMoviePopular(): MoviePopular {
return api.fetchMoviePopular()
}
override suspend fun fetchFaves(): Faves {
return api.fetchFaves()
}
}
I am wanting to call the above 3 api at the same time with the following condition: if the 1st api fails, the following 2 apis will not be called, but if the 1st api succeeds, the 2nd api fails, still call the 3rd API In short, if the 1st api fails, don't call the rest of the apis, but if the 2nd api fails, continue to call other apis
fun fetchAll():Triple<Movie,MoviePopular,Faves> = supervisorScope {
val movieDeferred = async { fetchMovie() }
val moviePopularDeferred = async { fetchMoviePopular() }
val favesDeferred = async { fetchFaves() }
val movie = movieDeferred.await()
val moviePopular = moviePopularDeferred.await()
val faves = favesDeferred.await()
return@supervisorScope Triple(movie,moviePopular,faves)
}
so can anyone help me to solve this problem.Ryan Smith
02/22/2023, 11:39 PM// MyRepository.kt
class MyRepository<T>(coroutineScope: CoroutineScope) {
private val scope = couroutineScope + Dispatchers.Default
private val dataSource: DataSource<T> = DataSource()
fun add(newValue: T) {
scope.launch {
dataSource.new(newValue)
}
}
}
// Example usage in a Compose Desktop app
// Main.kt
@Composeable
@Preview
fun App() {
val appScope = rememberCoroutineScope { Dispatchers.Main }
val repository = MyRepository(appScope)
MainScreen(repository)
}
Lukas Lechner
02/23/2023, 11:38 AMDaniele Segato
02/23/2023, 4:43 PM@JvmField
internal val CORE_POOL_SIZE = systemProp(
"kotlinx.coroutines.scheduler.core.pool.size",
AVAILABLE_PROCESSORS.coerceAtLeast(2),
minValue = CoroutineScheduler.MIN_SUPPORTED_POOL_SIZE
)
and
internal val AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors()
does this means that the Default dispatcher contains both big and little cores? and assign work to do to each or the other just depending on the order they gets in?
Anyone has information on how this works? Do I have any control on which profile gets chosen as a developer or am I misinterpreting the all thing and the cores are swapped under the hood by the OS transparently?
Thanks in advance to whoever can help me gain a better understanding on this topic.julian
02/23/2023, 5:58 PMColton Idle
02/23/2023, 6:36 PMclass NetworkBackedBookRepository(
private val api: ApiService,
) : BookRepository {
override suspend fun getBook(id: String): Book? {
val result = api.getBookById(id).execute()
return result.body()?.firstOrNull()
}
}
jean
02/24/2023, 9:47 AMclass PaymentViewModel(...) : ViewModel() { // in an android app
private val _state = MutableStateFlow<PaymentStatus>()
val state = _state.asStateFlow()
fun pay() {
...
}
private fun payWithCard {
paymentWithCard() // returns a flow of PaymentStatus
}
private fun payWithApp {
payWithApp() // returns a flow of PaymentStatus
}
}
How can I update _state
with the data coming from paymentWithCard()
and paymentWithApp()
? Do I have to use collect { … }
on each of them and manually update the state?kevin.cianfarini
02/25/2023, 3:40 PMadvanceTimeBy
but since delays are skipped, using it doesn't make a difference.
Is testing that currentTime
has been incremented as you expect the proper approach?fengdai
02/28/2023, 3:34 AMDaniele B
02/28/2023, 5:31 PMimplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
on Android, the app works without the need of adding the android-specific coroutine package on androinMain
on Desktop, it gives me this error:
Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher, e.g. 'kotlin-coroutine-android' and ensure it has the same version as 'kotlin-coroutine-core'
what is the reason why on Android, the target specific package is not needed?Jason Hartley
02/28/2023, 5:52 PMTim Malseed
03/01/2023, 1:21 AMList<Flow<String?>>
I’d like to emit the latest value from the first flow in the list - unless that value is null, in which case I’d like to move to the next flow.
Does anyone know how to achieve this?ubu
03/01/2023, 11:43 AMoverride val view: Flow<WidgetView> = combine(
expandedBranches, isWidgetCollapsed
) { paths, isWidgetCollapsed -> Pair(paths, isWidgetCollapsed)
}.flatMapLatest { switchToNewFlow() based on Pair }
I think that creating a pair is kind of redundant. But every time either of these two flows emits a new value, I need to switch to a different flow. Thanks!Christophe Dongieux
03/02/2023, 8:18 PM@Test
fun `Foobar is foo`() = runTest {
val job = launch {
println("Coroutine 1: Going to sleep for 3000. currentTime = $currentTime")
delay(3000)
println("Coroutine 1: Delay is over. currentTime = $currentTime")
}
launch {
println("Coroutine 2: Going to sleep for 1000. currentTime = $currentTime")
delay(1000)
println("Coroutine 2: Delay is over, cancelling other Coroutine. currentTime = $currentTime")
job.cancel()
}
advanceTimeBy(500)
println("advance 500: currentTime 1 = $currentTime")
advanceTimeBy(500)
println("advance 500: currentTime 2 = $currentTime")
advanceUntilIdle()
println("advanceUntilIdle: currentTime 3 = $currentTime")
assertEquals(1000, currentTime)
}
The output is:
Coroutine 1: Going to sleep for 3000. currentTime = 0
Coroutine 2: Going to sleep for 1000. currentTime = 0
advance 500: currentTime 1 = 500
advance 500: currentTime 2 = 1000
Coroutine 2: Delay is over, cancelling other Coroutine. currentTime = 1000
advanceUntilIdle: currentTime 3 = 3000
expected:<1000> but was:<3000>
Expected :1000
Actual :3000
As Coroutine 1 is canceled I don’t understand why currentTime 3
is 3000 instead of 1000.Rohan Maity
03/03/2023, 10:06 AMprivate fun CoroutineScope?.launchWithNullCheck(
block: suspend () -> Unit
) {
this?.let {
Log.d("FUI", "Scope not null")
val job = launch {
Log.d("FUI", "executing block not null")
block()
}
Log.d("FUI", "job isActive ${job.isActive}, isCompleted: ${job.isCompleted}, isCancelled: ${job.isCancelled}")
}
}
Colton Idle
03/04/2023, 7:32 AMPatrick Steiger
03/05/2023, 11:55 PMsubscriptionCount
a property of MutableSharedFlow
instead of SharedFlow
?Bradleycorn
03/06/2023, 9:24 PMobject MyObject {
suspend fun repeatWork() {
while (true) {
// do something
delay(5_000L)
}
}
}
That’s fine, but now multiple things can call it, and do “multiple copies” of the work:
class SomeClass {
fun doWork() {
someClassScope.launch { MyObject.repeatWork() }
}
}
class AnotherClass {
fun doAnotherWork() {
anotherClassScope.launch { MyObject.repeatWork() }
}
}
SomeClass().doWork()
AnotherClass().doAnotherWork()
I’m trying to ensure that only one “instance” of the repeatWork routine is running at a time, no matter how may things try to call it. I was thinking something like this:
object MyObject {
private var repeatWorkJob: Job? = null
suspend fun repeatWork() = coroutineScope {
if (repeatWorkJob?.isActive == true) return
repeatWorkJob = launch {
while (true) {
// do something
delay(5_000L)
}
}
}
}
Is this the best/right way to ensure there’s only one “instance” of the repeatWork routine running at one time?ursus
03/07/2023, 2:55 PMclass FooViewModel(private val appScope: CoroutineScope) : ViewModel() {
fun fooClicked() {
viewModelScope.launch {
delay(2000)
withContext(appScope.coroutineContext) { <---------------------------
// Should run even when view user clicks back (i.e. view model cleared)
delay(2000)
}
}
}
}
Is this a correct way to run something even after view model scope is cancelled? (view model cleared on back press)
I was used to just appScope.launch { .. }
i.e. to launch a new couroutine in the "higher" scope explicitly
This way of withContext
seems to work as well but feels wrong
Opinions? Doesn't it leak viewmodel this
during the lambda execution?Sam
03/07/2023, 11:11 PMCancellationExceptions
... They're not aliases of each other... Does either one work?natario1
03/08/2023, 10:46 AMkotlinx.coroutines
release is scheduled for?
I see very little activity in the master branch, previous release was on July 2022. At the same time we are eager to try the new android native targets. kotlinx-atomicfu
made a special release just for these, could coroutines do the same?Zoltan Demant
03/09/2023, 6:10 AMStateFlow
? Id think that the first emission comes through, but if you then edit the class and emit it anew, nothing will come through given how StateFlow compares equals before emitting new items?Robert Jaros
03/09/2023, 2:35 PMTower Guidev2
03/09/2023, 4:32 PMVsevolod Tolstopyatov [JB]
03/09/2023, 4:50 PMChannel
, Mutex
and select
implementations
• JPMS support
• Merge of kotlinx-coroutines-core
and kotlinx-coroutines-jdk8
• Partial stabilization and notable improvements of kotlinx-coroutines-test
• More K/N support: all official targets, better dispatchers, <http://Dispatchers.IO|Dispatchers.IO>
And many more! Full changelog: https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.7.0-BetaDaniel
03/10/2023, 6:12 PMsuspend fun Logout(token: String) {
val userId = appService.currentUser!!.id ///// this will execute 1st
realm.write { ///// this will execute 2nd
var user = query<UserInfo>("_id = $0", userId).first().find()
if (user != null) {
user = findLatest(user)!!.also {
it.FCMToken.remove(token)
}
copyToRealm(user)
}
}
withContext(Dispatchers.Default) { ///// this will execute 3rd
realm.syncSession.uploadAllLocalChanges() ///// this will execute 4rd
appService.currentUser?.logOut() ///// this will execute 5th
}
}
Are they executed in a linear way?Kshitij Patil
03/14/2023, 5:16 AMSlackbot
03/14/2023, 11:19 AMnatario1
03/14/2023, 12:16 PMclass Processor {
private val condition1 = MutableStateFlow(false)
private val condition2 = MutableStateFlow(false)
private suspend fun process(): Processed { ... }
init {
someScope.launch {
combine(condition1, condition2) { a, b -> a || b }
.collectLatest { process() }
}
}
fun setCondition1() { condition1.value = true }
fun setCondition2() { condition2.value = true }
}
When the user changes one of the conditions, I would like to
• know if this change did not trigger a process()
(for example, throw if not)
• return something like a Deferred<Processed>
to be (optionally) awaited.
Does anyone have any idea on how to achieve this?jean
03/14/2023, 12:52 PMawaitClose
from my unit test ? I tried to cancel testScope
but that triggers a ClosedReceiveChannelException: Channel was closed
since turbine gets also canceled.
private fun someApiCallbackToFlow(api: API) = callbackFlow {
val callback = object : ApiCallback {
override fun next(data: Int) {
trySend("Success")
}
}
api.register(callback)
awaitClose {
println("callback unregistered")
api.unregister(callback)
}
}
@OptIn(ExperimentalTime::class)
@Test
fun test() = testScope.runTest {
val api = SomeApi()
val flow = someApiCallbackToFlow(api)
flow.test {
assertEquals(1, api.callbacks.size)
api.getData()
assertEquals("Success", awaitItem())
// how can I check there isn't any callback here?
}
}
jean
03/14/2023, 12:52 PMawaitClose
from my unit test ? I tried to cancel testScope
but that triggers a ClosedReceiveChannelException: Channel was closed
since turbine gets also canceled.
private fun someApiCallbackToFlow(api: API) = callbackFlow {
val callback = object : ApiCallback {
override fun next(data: Int) {
trySend("Success")
}
}
api.register(callback)
awaitClose {
println("callback unregistered")
api.unregister(callback)
}
}
@OptIn(ExperimentalTime::class)
@Test
fun test() = testScope.runTest {
val api = SomeApi()
val flow = someApiCallbackToFlow(api)
flow.test {
assertEquals(1, api.callbacks.size)
api.getData()
assertEquals("Success", awaitItem())
// how can I check there isn't any callback here?
}
}
Patrick Steiger
03/15/2023, 3:03 AMtest
runTest {
coroutineScope {
launch {
flow.test {
…
cancel()
}
}
}
// verify unregister
}
runTest {
var called = false
callbackFlow<Nothing> {
awaitClose { called = true }
}.test {
cancel()
}
assertTrue(called)
}
This passesjean
03/15/2023, 8:05 AM