Johnny
10/17/2021, 12:09 AMisActive
check here necessary to make sure the job wasn’t cancelled before running the code block? Or would coroutine handle it under the hood? Not sure how it prevents the race condition here
fetchDataJob = viewModelScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
val data = useDataUseCase.getData()
withContext(mainDispatcher) {
if (isActive) {
// code here shouldn't run if job was cancelled
// ...
}
}
}
K Merle
10/17/2021, 3:48 PMviewModelScope
while closing the screen. Network request gets canceled as coroutine scope is canceled. How do I send a network request upon closing the screen?Fabio Rafael da Rosa
10/18/2021, 8:31 AMmarcinmoskala
10/18/2021, 11:46 AMrunBlocking
is a coroutine builder, but its coroutine is bound to the thread, so its behavior is different from async
, launch
and produce
. Is there a name for coroutine builders except for runBlocking
?marcinmoskala
10/18/2021, 11:46 AMcoroutineScope
, withContext
, withTimeout
and supervisorScope
have very similar behavior and this group should have a name. In some places they are referenced as "Scoping functions", but I understand this can be confused with "Scope functions". What are your feelings about that? I am considering naming them "Coroutine scope function" or "Coroutine scoping functions".marcinmoskala
10/18/2021, 3:42 PMasync
and launch
start a coroutine. runBlocking
is less clear, but I would say, that even though what is start is not concurrent, it starts a coroutine, it is just bound to the thread. But how about coroutineScope
? I think that they do not really start any new coroutine, just like suspending functions do not start a coroutine, but instead they can suspend the coroutine on which they are started. I just wanted to confirm if there are no disagreements here.Colton Idle
10/20/2021, 9:09 AMjwass
10/21/2021, 12:21 PMGlobalScope.launch { runBlocking { setupRoutines() }}
there's a field
val resolveChan = Channel<Envelope>(PARALLELISM * 2) // PARALLELISM = 200
and setupRoutines()
does:
jobs = (0..PARALLELISM).map {
launch(CoroutineName("read-only-$it") + <http://Dispatchers.IO|Dispatchers.IO>) {
<http://logger.info|logger.info>("Start RRO thread ${Thread.currentThread().name} from ${resolveChan}")
try {
for (envelope in resolveChan) {
try {
<http://logger.info|logger.info>("> RRO ${envelope.trace} ${Thread.currentThread().name}")
(try catch is mostly for debugging at this point)
My class has a public method that enqueues envelopes:
suspend fun ingestAsync(envelope: Envelope) {
<http://logger.info|logger.info>("> Ingest async ${envelope.trace} to $resolveChan")
resolveChan.send(envelope)
<http://logger.info|logger.info>("< Ingest async ${envelope.trace} to $resolveChan")
}
My problem is that the envelopes never seem to get received in the for loop above, and there are no exceptions.
Startup is fine:
Start RRO thread DefaultDispatcher-worker-13 @read-only-199#202 from ArrayChannel@46794b2a{ReceiveQueued,queueSize=159}(buffer:capacity=400,size=0)
then it adds envelopes to the channel without errors, but they are never picked up.
> Ingest async cdf83ca6-c756-49e0-a3ee-a4e309c4942a to ArrayChannel@46794b2a{ReceiveQueued,queueSize=94}(buffer:capacity=400,size=0)
< Ingest async cdf83ca6-c756-49e0-a3ee-a4e309c4942a to ArrayChannel@46794b2a{ReceiveQueued,queueSize=93}(buffer:capacity=400,size=0)
That confirms that the object id for the channel is the same. I do notice that the size
says at 0 the whole time, which is weird?Ginto Philip
10/21/2021, 2:32 PMfun main(args: Array<String>) {
download()
print("from main")
}
fun download(){
runBlocking {
coroutineScope {
launch {
delay(10000)
println("from coroutine")
}
}
}
}
3. I want the "from main" to be executed first. How can I do that? . Should I call download() from a new thread?taer
10/21/2021, 3:02 PMReceiveChannel.onReceiveCatching
new goodness. But this project will be used by 1.4 people. Via the magic of gradle, they'll be upgraded to 1.5.2 coroutines lib running on 1.4. Is that kosher?Saiedmomen
10/21/2021, 9:53 PMScope
to stateIn
operator when the MutableStateFlow
constructor doesn't need a scope?ursus
10/22/2021, 6:59 PMdata1
, data2
, data3
types. They're not related. For reasons I need to normalize this into 3 tables, and cannot be kept as json together.
But now, how should I query all three reactively together, in a way that the listener emits only once, same way join changes do?
I could do
combine(
data1Query.asFlow().mapOneOrNull(),
data2Query.asFlow().mapOneOrNull(),
data3Query.asFlow().mapOneOrNull()
)
etc, but as I said, all 3 get updated together in a transaction. Which means there would be bunch on unwanted emits for combine
when update happens
I know I could debounce
it, but feels wrong.
Is there a way library could handle this, same way it does for joins? Or is debouncing this a standard solution?parth
10/22/2021, 7:54 PMSELECT * from A, B, C
WHERE A.id = B.id
AND B.id = C.id
K Merle
10/24/2021, 11:46 AMtursunov abdulbois
10/25/2021, 11:02 AMIvan Đorđević
10/26/2021, 9:19 AMSharedFlow
that caches values (like replayCache
) but DOESN'T play them back automatically to new subscribers?dimsuz
10/26/2021, 10:59 AMMihai Voicescu
10/26/2021, 6:43 PM@OptIn(ObsoleteCoroutinesApi::class)
class ActorDelegate<T>(coroutineScope: CoroutineScope, create: () -> T) {
class Package<T, R>(val block: T.() -> R) {
val def = CompletableDeferred<R>()
}
private val channel = coroutineScope.actor<Package<T, Any>> {
val t = create()
channel.consumeEach {
it.def.complete(it.block(t))
}
}
suspend fun <R> withContext(block: T.() -> R): R {
val pkg = Package(block)
channel.send((pkg as Package<T, Any>))
val r = pkg.def.await()
return r as R
}
}
fun <T> CoroutineScope.actorDelegate(create: () -> T) = ActorDelegate<T>(this, create)
class CoroutineMutableList(coroutineScope: CoroutineScope) {
private val actorDelegate = coroutineScope.actorDelegate { mutableListOf<Int>() }
suspend fun size() = actorDelegate.withContext { size }
suspend fun contains(element: Int) = actorDelegate.withContext { contains(element) }
suspend fun get(element: Int) = actorDelegate.withContext { get(element) }
suspend fun add(element: Int) = actorDelegate.withContext { add(element) }
// rest...
}
Minsoo Cheong
10/27/2021, 8:42 AMursus
10/28/2021, 1:58 AMinit
block, or should there be some explicit onCreate function instead?
I'm not really a fan of the former, since now the ctor is called on whatever random thread DI decides
However the latter you can mistakenly call mutiple times etc
What's your preference?Florian
10/28/2021, 10:44 AMonTaskSelected
calls first()
on the selectedTask
flow. But apparently, I can't do that in the init
block of this ViewModel because then the Flow is not initialized yet. So the temporary collect
makes sure that the selectedTask
Flow is ready.
ViewModel {
init {
if (taskIdToSelect != null && taskIdToSelect != Task.NO_ID) {
CoroutineScope(Dispatchers.Main).launch {
selectedTask.collect {
onTaskSelected(taskIdToSelect.toLong())
cancel()
}
}
}
}
Ravin Jain
10/29/2021, 1:00 AMcoroutineScope
gets cancelled when the Job created from viewmodelscope.launch
is cancelled ?Ciprian Grigor
10/29/2021, 2:35 PMgroostav
10/31/2021, 10:54 PMFlow()
and somebody called first()
, we should not cancel the remaining elements. The remaining elements should instead be produced and simply left un-consumed). You do have to kick it off. If you forget about it in most cases it'l complete normally but it some it will hang open, like a resource that needs to be disposed.
Should I make this thing into a ReceiveChannel
or a Flow
?Philip Dukhov
11/01/2021, 12:36 PMsuspend fun some(argument: Int) : Unit {
// process
}
fun service(some: (Int) -> Unit) {
some(1)
}
And I'd like to pass some
by reference like this:
val coroutineScope = ...
service(::some::launchIn(coroutineScope))
The function launchIn(coroutineScope)
is what I'm looking for, am I missing something built in, or is there a way I can create it?CLOVIS
11/01/2021, 5:36 PMrook
11/01/2021, 5:57 PMflowOn
. I’m working up against an API, so I’m not ruling that out, but the basic premise is
fun <T> CoroutineScope.someCall(): Flow<T?> {
val api = getThreadLockedApi()
api.apiCall()
.toFlow()
.onComplete { api.threadLockedCleanUp() }
.flowOn(coroutineContext)
.map {}
}
My consumer looks something like
object Consumer {
private val coroutineScope = CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO> + SupervisorJob())
val someCallFlow: Flow<MyType>
get() = coroutineScope.someCall()
}
I’m getting an exception of Flow context cannot contain job in it
. I get the sense that the argument for flowOn
must be a Dispatcher -only-. But I’m having a hard time isolating or reproducing the issue. Regardless of the core issue, the thing I’m trying to accomplish is ensure that the onComplete
block is run in the same thread as the someCall()
local block. Am I using the correct technique, or is there something I’m missing?Rafal
11/02/2021, 7:47 AMListAdapter
. Is onAttachedToRecyclerView/onDetachedFromRecyclerView
valid place to manage the scope?
class CoroutineAdapter: ListAdapter<AdapterItem, AdapterViewHolder>() {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
coroutineScope.launch {
// stuff made here
}
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
coroutineScope.coroutineContext.cancelChildren()
}
}
leosan
11/02/2021, 11:01 AMNathan Bedell
11/02/2021, 4:29 PM