Move threading concerns to API surface
The scanning implementation is making decisions on threading that aren't optimal:
- It scans for view roots from the calling thread
- But then it always performs the scanning of each hierarchy from the main thread (but only if they're Android views). There's one post to the main thread per Android root view and each gets 5 seconds for the traversal, so if the main thread is blocked and we have N windows we could wait N * 5 seconds.
This change moves these decisions around threading behavior to the callers, with a default provided configuration that matches the previous behavior, except there is a single post and the root scanning is done as part of it.
while also introducing less new API surface, by using coroutines
Oxymoron spotted!
Using coroutines means adding a dependency that's not necessarily used by all consumers yet, so that would indeed introduce a lot of new API surface (from a dependency) :)
Aside from that, I wonder, what's the behavior of this when you are indeed on the main thread:
withTimeout(5.seconds) {
withContext(Dispatchers.Main.immediate) {
continue()
}
}
I can't think of a way to implement timeout when calling code synchronously (and the code within those coroutines would be non suspending), so probably the timeout would only work if not on the main thread here?
Aside from that, I wonder, what's the behavior of this when you are indeed on the main thread:
withTimeout(5.seconds) { withContext(Dispatchers.Main.immediate) { continue() } }I can't think of a way to implement timeout when calling code synchronously (and the code within those coroutines would be non suspending), so probably the timeout would only work if not on the main thread here?
I'm not sure I understand what you mean? Do you mean if the continue block has no yielding? That's just a feature of co-operative multitasking (or 'non-preemptive' if you'd rather), you have to co-operate.
I don't see what being or not being on the main thread has to do with this?
That's just a feature of co-operative multitasking (or 'non-preemptive' if you'd rather), you have to co-operate.
Indeed. And AFAIK the current code does not cooperate (e.g. no suspending functions while traversing the view hierarchy) so the timeout would work if you called scan from a background thread but not if you called it from the main thread.
Which is exactly the same thing as what's happening without coroutines, except that the distinction of "is this called from the main thread" is more visible in the impl.