Hi, ```Activity { private val scope = MainScope(...
# coroutines
u
Hi,
Copy code
Activity {
	private val scope = MainScope()

	onCreate {
		scope.launch {
			userDao.user
				.collect {
					if (it == null) {
						resetBackstack()
					}
				}
		}
	}
}

SomeScreenViewModel {
	private val scope = MainScope()

	fun init() {
		scope.launch {
			userDao.user
				.collect {
					...
				}
		}
	}
}
UserDao.user
emits on its io dispatcher, both activity and some screen viewmodel are driven by main threaded scope (android) Occasionally in crashlytics I see crashes related, basically to the fact that the screen collects the emit first Is there a way I could enforce order of collections? (I presume if it were a replayed hot Flow, then order would be the order of subscriptions, however I presume that posting to main thread will always be race-y?)
m
Hey, yes, I think so. The stupid option might be to add a
delay
, even a very small one. A solid one might be to make another
MutableStateFlow
where the first one emits when the first one is done. Although in this case it should be enough to just add
if (it == null) return@collect
on the second one.
u
I simplified it a bit more than there is to it tbh,just looking for ordering guarantee or not, rxjava had ot
d
Interesting. What it looks like to me 'at the core' is not collect/emit related as much as you have 2 sync blocks of code that depend on the order they are running but are doing nothing to enforce it -- not much different then 2 threads that are data dependent. One solution to that problem is synchronization , such as a mutex, and associated appropriate checks like checking for null in both. Flows don't eliminate problems associated with the collecting code being dependent on the order of other collectors -- that's the whole point, to facilitate *independent collectors' not 'dependent collectors'
u
How would I enforce order via synchronization? Main thread is "serialized" so first one post will always go first, which in my mind if I can guarantee activity collect emits first, then it should work always, no? Presuming collectors are keps in a List; and just forlooped
d
The order up to the first suspend function is deterministic, after that no. I cant 100% follow your code, but from my view, the first line INSIDE each launch block may execute in arbitrary order . You can detect with a simple var -- (assuming all on same thread) (both samples are 'rough' concept code : may need tweaking)
var mefirst = -1
fun meFirst() { if( mefirst < 0 ) mefirst = 0 else println("second") }
fun meSecond( if( mefirst < 0 ) mefirst  = 1 else println("second") }
If on different threads needs an AtomicInt or Mutex To enforce order something like a semaphore can work
val sem = Semaphore(1,1)
fun meFirst() { doStuff() ; sem.release() }
fun meSecond{ sem.aquire() ; doStuff() }
So would a 'token' coroutine that is waited for say
fun meFirst() = launch( CoroutineStart.LAZY ) {  doFirstStuff() }
val meFirstJob = meFirst()
fun meSecond() = launch {
meFirstJob.join()
doSecondStuff()
}
I put in LAZY for no good reason -- it would work otherwise but as above it would be guarenteed to both finish first and start first .