I have an exam tomorrow and I want to study the following pdf. My exam only contains the theorical parts of this pdf, and not the coding part. I want you to write a comprehensive and structured recap,  containing details and not very short, out of this pdf file in a way to be easily memorizable.

© G. Malnati, C. Barberis, 2012-23
Multi-threading in Android
2022-23© G. Malnati, C. Barberis, 2012-23 2
Multi-threading in Android
• When an application is started, the operating system creates a
process and, inside it, a "main" thread
o That manages all application components, distributing the events related
to their life-cycle
• This thread creates a message queue, initializes the objects
defined in the manifest-file and then begins an infinite loop
o It extracts a message from the queue and delivers it to its recipient
o This may cause the insertion of new messages at the end of the queue© G. Malnati, C. Barberis, 2012-23 3
Multithreading in Android
• Several other threads are spawned automatically from the main
one:
they are managed by the OS
o Users never directly interact with them and hardly notice their presence
o Their purpose is to support the execution abstraction either of the
Dalvik/ART virtual machine or of the overall OS component framework© G. Malnati, C. Barberis, 2012-23 4
JVM-level threads
• GC
o Low priority garbage collection thread
• JDWP
o Support debugging and memory inspection
• Compiler
o Provide just in time compilation of code
• ReferenceQueueD, FinalizerDeamon, FinalizerWatchd
o Support object finalization and memory cleanup© G. Malnati, C. Barberis, 2012-23 5
Android system threads
• Binder_X threads
o Handle incoming intents and other IPC requests
• Signal catcher
o Handle quit, usr1 and usr2 Linux signals
• GL updater
o Handle hardware accelerated UI
• hwUITask
o Handle incoming messages from UI© G. Malnati, C. Barberis, 2012-23
The Android main thread 1/3
6
Out
In
Message
queue
val q = MessageQueue();
InitSystemObjects();
while (true) {
val m=q.getMessage();
dispatchMessage(m);
}
Pseudo-code© G. Malnati, C. Barberis, 2012-23 7
The Android main thread 2/3
• The main thread is responsible of
o Instantiating the Application and Activity objects
o Notifying them the events related to their life cycle
o Sending drawing requests to the views
o Delivering the events related to user interaction to the corresponding
listeners
o …as well as several other tasks
• The access to the queue is synchronized
o Other threads (including the operating system’s ones) may insert new
messages...
o ... As long as there is no pending dispatching operation
o In this case, the system waits a few seconds, then it forces the termination
of the application© G. Malnati, C. Barberis, 2012-23 8
The Android main thread 3/3
• It is necessary that all tasks, carried out in the main thread,
terminate in a short time
o To prevent the displaying of the
"Application not responding"
dialog box
• If you need to perform a long-lasting task, you should either
create a new thread…
o And delegate to it its execution
• …or use a coroutine
o Which, in turn, relies on the multi-threading subsystem© G. Malnati, C. Barberis, 2012-23 9
Programming abstractions
• User programs may benefit of multithreading as well
• Multithreading may be approached using the Java standard
abstractions
o Via the Thread class, and java.util.concurrent.* abstractions (locks,
concurrent collections, cyclic barriers, atomic values, …)
• In order to support the programmer in the development of
concurrent programs, Android provides several useful
abstractions
o Like Looper and AsyncTask
o The usage of these abstractions is highly encouraged, since they represent
the skeleton of the OS infrastructure© G. Malnati, C. Barberis, 2012-23 13
Accessing shared state
• When two (or more) threads need to access the same variable a
conflict may arise
o Read-Modify-Write operations may lead to inconsistent values
• A lock can be used to guarantee mutual exclusion between
threads
o Only one thread at a time can hold the lock
o If other threads are willing to hold it, they are temporarily suspended, until
the one holding it leaves the block© G. Malnati, C. Barberis, 2012-23 15
Problems related to threads (1)
• All threads access the same address space
o In particular, there is only a single heap where objects are allocated
• If an object reference is known to two or more threads, the
object is shared
o The threads may communicate storing values in its attributes
• This gives rise to interference, leading to unexpected results, if
no synchronization is performed© G. Malnati, C. Barberis, 2012-23 16
Problems related to threads (2)
• By default, threads do not provide ways to asynchronously
communicate among them
o Accessing a shared state is the only viable solution
• If a thread needs to know whether some state has changed,
either polling or blocking waiting is to be used
o Making it difficult to keep things working efficiently© G. Malnati, C. Barberis, 2012-23 17
Problems related to threads (3)
• Secondary threads are not aware of the application lifecycle
o Nor of any other callbacks received inside the main thread
• A part of the Android framework is ONLY accessible from the
main thread
o Typically, the View hierarchy
o Any attempt to perform operations entailing this kind of objects from a
secondary thread will give rise to an exception, terminating the current
process© G. Malnati, C. Barberis, 2012-23 18
Problems related to threads (4)
• Thread are extremely easy to create, but hard to cancel
o The only supported mechanism for thread cancellation relies on
cooperatively polling the interrupted flag provided by Thread objects
o But its semantics is complex and it is subject to a large number of border
cases that need manual intervention by the programmer© G. Malnati, C. Barberis, 2012-23
Dealing with asynchronous tasks in
Android
19
Java native
Thread +
Synchronization
Android
extensions
3rd party
libraries
Callback
Reactive
Streams© G. Malnati, C. Barberis, 2012-23 20
Android threading extensions
• Looper / Handler / MessageQueue
o Mechanism on which all applications are built
o Robust and powerful
o Complex
• AsynchTask
o Formerly proposed as a general solution
o Now deprecated
• Coroutines
o Kotlin-only powerful solution© G. Malnati, C. Barberis, 2012-23
Handler
Handler
Handler
Handler
The low-level Looper API
21
Looper
Message
Queue
N 1
1 1
Message
Message
Message
1 N
Java thread© G. Malnati, C. Barberis, 2012-23 22
android.os.Looper (1)
• Class that manages a message queue associated with a single
thread
o The queue is not directly accessible to the programmer, but is it created
through the Looper.prepare() static method
• The thread that invokes this method becomes the owner of the
queue
o When the Looper.loop() static method is called, an infinite loop starts,
waiting for messages from other threads
• The main thread of an application is built with this schema© G. Malnati, C. Barberis, 2012-23 23
android.os.Looper (2)
class MyLooper :Thread() {
private lateinit
var h : Handler
private
val cdl = CountDownLatch(1)
override fun run(){
Looper.prepare()
h = MyHandler()
cdl.countDown()
Looper.loop()
}
fun getHandler(): Handler {
cdl.await()
return h
}
}
Create a queue
associated with the
current thread
Create a message
processor, through
which messages and
tasks can be sent
Performs a loop that
continuously waits
(without consuming
CPU) for the next
message,
and then dispatches it© G. Malnati, C. Barberis, 2012-23 24
android.as.Looper (3)
• Generally, looper objects are only accessible from their own
thread
o Via method Looper.myLooper()
• Main looper is an exception
o It is accessible from any thread, via Looper.getMainLooper()
• Loopers can be terminated via their quit() method
o Or via quitSafely() //requires API 18© G. Malnati, C. Barberis, 2012-23 25
android.os.MessageQueue
• Unbounded linked list of messages to be processed by the
consumer thread
o Every looper (and thread) has at most one MessageQueue
• It is possible to retrieve the MessageQueue for the current
thread via
o Looper.myQueue();© G. Malnati, C. Barberis, 2012-23 26
android.os.Handler (1)
• A class that provides a thread-safe interface for inserting and
processing of new requests in a looper queue
o An Handler object is bound to the implicit queue associated with the
thread in which it was created
• The request may be constituted by a Runnable or a Message
object
o In the first case, the handler will execute the associated run() method
o In the other case, it will process it via its own handleMessage(Message m)
method
• In both cases, processing will happen inside the associated
looper thread© G. Malnati, C. Barberis, 2012-23
android.os.Handler (2)
27
• The requests can be queued immediately
o post(Runnable r)
o sendMessage(Message m)
• ... Or after a given time interval
o postDelayed(Runnable r, long delay)
o postAtTime(Runnable r, long time)
o sendMessageDelayed(Message m, long delay)
o sendMessageAtTime(Message m, long time)© G. Malnati, C. Barberis, 2012-23 28
android.os.Handler (3)
• The handler mechanism can be used to asynchronously
communicate with a thread
o Provided it is a looper
• A looper thread can be associated with many different handler
o But they all insert messages in the same queue
o When the message will be picked up, it will be processed by the handler
through which it was inserted© G. Malnati, C. Barberis, 2012-23 29
android.os.Message
• Models an event described by an integer value, a pair of
(integers) parameters and an eventual object to be delivered to
the recipient
o The use of integer values ​​makes the use (and reuse) of objects of this type
efficient
• Given the allocation and releasing cost of new items, the
operating system maintains a queue of messages that are not in
use
o You get a message via Message.obtain()
o You can release it via recycle()© G. Malnati, C. Barberis, 2012-23 30
The producer/consumer pattern
• Looper threads naturally lend themselves to implement the
producer/consumer pattern
o A producer thread asynchronously generates pieces of information, storing
them in Message objects
o Messages are inserted in the MessageQueue of the consumer via Handler
sendMessage() method
o Looper (consumer) thread extracts one message at a time and dispatches it
to the handler that was used to post it in order to process it© G. Malnati, C. Barberis, 2012-23
The producer/consumer pattern
31
Producer
thread
Message
Queue
sendMe
ssage(
m)
h:Handler
Consumer
thread
Looper
handle
Messag
e(m)
loop()© G. Malnati, C. Barberis, 2012-23 35
Managing typical problems 1/2
• Only the main thread can access objects of the graphical
interface
o If a secondary thread tries to operate on them, the application is
terminated with an exception
• A mechanism that allows the secondary thread to notify its
results to the main thread is required
o The main thread will then show them
FATAL EXCEPTION: Thread-8 E/AndroidRuntime(374):
android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can
touch its views.© G. Malnati, C. Barberis, 2012-23 36
Managing typical problems 2/2
• Storing a value in an activity attribute is not usually a good
solution
o The main thread would not notice this change and, unless an external
event that causes the redesign of the interface occurs, the view would
remain unchanged
• It is necessary that a new event is inserted in the message queue
o When the main thread will process it, it will understand that the secondary
thread has finished and what are its results© G. Malnati, C. Barberis, 2012-23 37
Sending messages to the main thread
1/3
• Android provides five different alternatives
o Each with its own strengths and weaknesses
• activity.runOnUiThread(r: Runnable)
o When this method is executed, if the current thread is not the main one, a
new message that encapsulates a Runnable object is inserted into the
queue
o When the message will be processed, the main thread invokes the run()
method of its parameter, and the contained code will be executed
o It requires the secondary thread to hold a reference to the current ongoing
activity© G. Malnati, C. Barberis, 2012-23 38
Sending messages to the main thread
2/3
• view.postRunnable(r: Runnable)
o Inserts the Runnable object in the message queue
o It can be called from any thread as long as the view is displayed inside a
window
• view.postDelayed(r: Runnable, l: Long)
o Similarly to the previous case, it inserts the object into the queue, but it
will not be processed before an interval equal to "l" milliseconds
o In this case, too, the view must be connected to a window and be visible© G. Malnati, C. Barberis, 2012-23 39
Sending messages to the main thread
3/3
• Use instances of the Handler class, created in the main thread,
and queue messages via
o sendMessage(…)
o sendMessageDelayed(…)
o sendMessageAtTime(…)
o sendMessageAtFrontOfQueue(…)
• Or request the execution of a Runnable object via
o post(…), postDelayed(…), postAtTime(…), postAtFrontOfQueue(…)© G. Malnati, C. Barberis, 2012-23 41
Incorporating an handler thread
• Handler threads can safely be incorporated into standard
components, binding their lifecycle to the component one
o The HandlerThread is created in the onCreate() method and quitted in the
onDestroy() one
• By creating HandlerThread subclasses, it possible to expose
convenience methods to simplify custom operations
o While guaranteeing ordered execution of requested messages© G. Malnati, C. Barberis, 2012-23 43
HandlerThread rationale
• Just a “normal” Thread which sets up the internal message passing
mechanism automatically
o No need to init a Looper manually…
• Applicable to many background execution use cases, where sequential
execution and control of the message queue is desired
o Using the constructor with the name argument simplifies debugging
• Started in the same way as a Thread → start()
• Terminated either with quit() or quitSafely()
o quit() - Terminates the Looper without processing any more messages in the
MessageQueue
o quitSafely() - Similar to the previous version but makes sure that the pending
messages that are due to be delivered are handled© G. Malnati, C. Barberis, 2012-23 44
AsyncTask
• Abstract and parametric class defining a tasks to be performed in
a secondary thread
o Offering at the same time, a set of methods that will be invoked from the
main thread in the appropriate time
o Deprecated in API level R, in favor of coroutines
o https://heartbeat.fritz.ai/replacing-asynctask-in-android-with-kotlincoroutines-to-handle-background-tasks-93108f8f2db© G. Malnati, C. Barberis, 2012-23 45
Kotlin coroutines
• Implementation of a long-time existing concept that allows to
simplify writing asynchronous code
o Managing long-running tasks that might otherwise block the main thread
and cause apps to freeze
o Providing main-safety, or safely calling network or disk operations from the
main thread© G. Malnati, C. Barberis, 2012-23 46
What coroutines do provide
• Possibility to express sequential logic, while coping with
asynchronous computation
o Sequential code is easier to write and to understand: no callback hell,
standard semantics for handling exceptions
o Asynchronous computation allows not to block on the main thread
• Composability and cancellability
o Several cooperating computations may be grouped in task and subtask,
easily tracking termination and cancelation
o Easy to refactor code to dial with more complex situations© G. Malnati, C. Barberis, 2012-23 47
Using coroutines
• Coroutines are part of the standard Kotlin library
o But they have some specific implementation for Android
o See also
https://github.com/Kotlin/kotlinx.coroutines
implementation "org.jetbrains.kotlinx:
kotlinx-coroutines-android:1.6.1"© G. Malnati, C. Barberis, 2012-23 48
Blocking functions
• Some operations may block the execution for an unknown time
o Anything concerning I/O and networking
o Delay functions
o Synchronizations
• When they are executed in the main thread, the application may
freeze
o Due to its impossibility to process further events in the message queue
• Executing these operations in a secondary thread is easy
o But collecting the results back in the main thread is hard
o It requires some form of synchronization and may easily conflict with
components' lifecycle© G. Malnati, C. Barberis, 2012-23 49
Having a sense of slowness
from "Asynchronous programming" by Kirill Bobrov, september
2020© G. Malnati, C. Barberis, 2012-23 50
Blocking vs. non blocking I/O
• Keeping a thread blocked while waiting for network data or
similar operations, makes the code easier to be written and
maintained
o Since it is possible to adopt an imperative coding approach, based on the
fact that the current computation remains "stable" (i.e., variables keeps
their values, the history of function invocation does not change, …) while
waiting
• Unfortunately, this also requires a lot of resources
o Each thread need to be pre-allocated together with its execution stack
• And it largely increases complexity, as well© G. Malnati, C. Barberis, 2012-23 55
Suspending functions
• To support these cases, Kotlin introduces the concept of
suspending functions
o Functions syntactically introduced by the keyword "suspend"
• They have the capability to request the OS to suspend the
ongoing computation
o Freezing the current state in a block of memory outside of the stack (the
context)
o Freeing the current thread, allowing it to perform another task, if available© G. Malnati, C. Barberis, 2012-23
• When a piece of code is compiled, two approaches can be used
by the compiler to implement function invocation
o Direct passing style
o Continuation passing style
56
Function invocation styles
prev_statement
c = f(a,b)
next_statement
...
prev_statement
call f(...)
c = <ret>
next_statement
…
f(a,b) suspend f(a,b, cont)
prev_statement
call f*(..., cont)
res -> {
c = res
next_statement
… }
return value
return
value© G. Malnati, C. Barberis, 2012-23 57
Continuation-passing style
• Using this style, the code AFTER the function is encapsulated into
another function, named continuation
o The continuation is passed as an extra parameter to the invoked function
• The function does not RETURN its own result, but a flag that
describes if the computation was suspended or did complete
o In case of suspension, it may be re-invoked later
o When it reaches its end, it invokes the continuation, passing its result value
as an argument© G. Malnati, C. Barberis, 2012-23 59
Continuation-passing style
• CPS is enabled in Kotlin by prefixing a function with the keyword
suspend
suspend fun someFunction (a: Int, b: Int): Int
public static final Object
someFunction(int a, int b, @NotNull Continuation c)
• The continuation will create an anonymous implementation of
the Continuation interface that encloses both the state of the
execution inside the function and the callback
The compiler transforms the code
above into the one below
Java© G. Malnati, C. Barberis, 2012-23 60
Continuation-passing style
• The code in the function has the opportunity to control when
and how the continuation is invoked
o Synchronously, in the same thread
o Asynchronously, in another thread© G. Malnati, C. Barberis, 2012-23 61
Continuation passing style
• A suspend function may invoke, in its body, both regular and
suspend functions
o The latter will introduce a suspension point
o A regular function cannot invoke a suspending one© G. Malnati, C. Barberis, 2012-23 62
Continuation passing style
• The compiler rewrites the body of a suspend function,
transforming it into a Finite State Machine
o If there are N suspension points, the FSM will have N+1 states
• The continuation will contain
o The current state of the FSM
o The set of local variables
o The result of the previous computation
o The callback to be invoked to return the value
o The coroutine context, that defines
▪ the Dispatcher responsible to invoke the continuation,
▪ the Job that conveys information about how the current coroutine relates to other (parent,
siblings, children) coroutines
▪ the ExceptionHandler that deals with failures© G. Malnati, C. Barberis, 2012-23 64
Coroutines
• A coroutine is an instance of a suspendable computation
o That is, a computation that can suspend at a given point, freeze its own
state in a context object, and later resume, possibly in another thread
• Coroutines are designed to support
o Asynchronous computations
o Futures
o Generators
o Channels
o …© G. Malnati, C. Barberis, 2012-23 65
Coroutines
• Like normal functions, coroutines are executed by a thread
o When they reach a suspension point, the state is frozen in the the context
and the function returns
o Thus the thread is detached from the coroutine, and it can perform other
computations
• If a suspended coroutine must be resumed, a thread will be
picked to invoke it again
o The coroutine context contains the information necessary to pick such a
thread and jump to the proper code label© G. Malnati, C. Barberis, 2012-23 66
Coroutines
• A suspending function makes it easier to switch from a thread to
another and back to the previous one
o The suspending function may be seen as a four gate block
suspend fun f(a,b)
call
return
suspend
resume© G. Malnati, C. Barberis, 2012-23 67
Coroutines
• The Suspend operation captures the current continuation (with
all local variables) and makes it available as the only argument to
a call-back routine
o This has the opportunity to arrange the execution of the blocking
operation in a different thread, which will – later on – invoke the
continuation
o When the call-back returns, the computation is actually suspended (the
invoking function returns), freeing the current thread
• When the other thread that was blocked performing the I/O will
proceed and invoke the continuation, the execution of the
suspend function can resume,
o Restoring the same state it had when it was suspended© G. Malnati, C. Barberis, 2012-23
Coroutines
68
suspend fun f(…) {
do_something()
withContext(Dispathers.IO) {
blockingTask()
}
more_work()
}
main
thread
main
thread
suspend
resume
Main thread is freed here, and may
process other tasks
When blockingTask() finishes, main
thread is resumed here© G. Malnati, C. Barberis, 2012-23 69
Execution flow
• Not every suspend fun invocation inside a coroutine will actually
suspend
o The compiler takes care of that by introducing a special return value to
mark a suspension
• Two typical cases where suspension occurs:
o delay(milliseconds: Int) – causes the current thread to be detached from
the coroutine and process other tasks: after the given amount of time, the
coroutine will be eligible for being resumed by any thread of the current
context
o withContext(ctx: CoroutineContext) { λ } – delegates the execution to any
thread inside the given context and frees the current thread which can pick
other tasks; current thread will later resume the coroutine execution,
when the lambda returns and it will be able to access the returned
value/exception© G. Malnati, C. Barberis, 2012-23 70
Coroutine contexts
• Coroutines require a context in order to be executed
• It defines
o Dispatcher – the set of threads used to execute it
o Job – the state of the computation of the coroutine
o CoroutineExceptionHandler – defines how exceptions thrown inside the
coroutine are handled
o CoroutineName – the name of the coroutine for debugging purposes
• Contexts are typically created adding the elements they are
made of
o val c: CoroutineContext = Dispatchers.IO + SupervisorJob()© G. Malnati, C. Barberis, 2012-23 71
Dispatchers
• Objects that define the thread pool used to invoke the coroutine
o A custom dispatcher may be created from an ExecutorService
• Class Dispatchers provide several ready made ones
o Dispatcher.Main
▪ Contains only the main thread
▪ Only available in Android and for GUI applications!
o Dispatchers.IO
▪ Contains a large thread pool, optimized for disk and network IO
▪ Used for reading/writing files, accessing databases, networking
o Dispatchers.Default
▪ Optimized for CPU intensive work off the main thread
▪ Used for task like sorting, parsing JSON, encrypting and decrypting, …© G. Malnati, C. Barberis, 2012-23 72
Invoking coroutines
• Because of their particular code structure, a suspend fun can
only be invoked from another suspend fun
o Or from a coroutine builder function
• Android provides several coroutine builder functions as
extension of a CoroutineScope
o fun launch(…) – Launches a new coroutine without blocking the current
thread and returns a reference to the coroutine as a Job
o suspend fun async(…) – Creates a coroutine and returns its future result
as a Deferred object
• A special coroutine builder function is available as a regular
function
o fun runBlocking(...) – Launches a new coroutine, blocking the current
thread until it and all its sub-coroutines finish© G. Malnati, C. Barberis, 2012-23 73
CoroutineScope
• Interface that encapsulates a CoroutineContext and defines a
set of extension functions useful for managing (creating,
destroying) a group of related coroutines
o Coroutines execution is confined inside the scope in which they were
created
o A specific scope is typically bound to those entities that have a welldefined lifecycle, so that when the entity is destroyed, the scope is
cancelled, actually terminating all contained coroutines that are still
alive
• Function CoroutineScope(...) creates a new scope
o Kotlin defines also a couple of ready made scopes, namely MainScope
and GlobalScope, which have some restrictions on their usage© G. Malnati, C. Barberis, 2012-23 74
Custom scopes
• Android defines a set of scopes for several of its abstractions
o viewModelScope - used for invoking suspend fun inside a ViewModel
o lifecycleScope - used for invoking suspend fun bound to any lifecycleowning object (activity, fragment, …)
o mainScope - used for creating a scope based on Dispatchers.Main
• Whenever the object bound to a custom scope reaches the end
of its lifecycle, the scope is cancelled
o Thus, all the coroutines that might still be running on behalf of it are
cancelled as well© G. Malnati, C. Barberis, 2012-23 75
Custom scopes
• Scopes and coroutines are
organized in tree-like
structure
o The root of the tree is always
represented by a scope
• Building children scopes
allows to group coroutines
that share a common
lifecycle
Coroutine
s
Context
s© G. Malnati, C. Barberis, 2012-23
Invoking coroutines
• When a coroutine is created inside a scope, a new context
context is created joining the scope context with any element
supplied as parameter of the creation function
o Then a new Job object is created and marked as a child of the Job
contained in the parent context
77© G. Malnati, C. Barberis, 2012-23 78
Jobs
• Representations of background tasks carried out by coroutines
• A job may have six states, expressed as a combination of three
boolean properties
o isActive, isCompleted, isCancelled
• Jobs may be organized in an hierarchy
o Each job may have 0 or more children
• CoroutineScope.launch(...) returns a job object representing the
currently started coroutine
o This job is child of the job contained in the context of the scope: thus
cancelling the context causes all ongoing jobs to be cancelled as well,
leading to cancellation of ongoing coroutines that are part of the scope© G. Malnati, C. Barberis, 2012-23
Job states
79
new active compl
eting
compl
eted
cance
lling
cance
lled
start
cancel / fail
finish
finish
wait children
cancel children© G. Malnati, C. Barberis, 2012-23 80
Jobs
• Jobs offer several methods to control their state
o fun start() – start the coroutine related to the job if not started yet
o fun cancel(cause) – cancel the job with an optional cancellation cause
o suspend fun join() – suspends the invoking coroutine until the job is
complete© G. Malnati, C. Barberis, 2012-23 81
Invoking async coroutines
• Another interesting coroutine builder extension function is
async(…)
o It allows to start a coroutine that is in charge of computing a value,
expressed by its returned value, an instance of Deferred<T>
• The value may later be obtained by invoking
deferred.await()
o It suspends the caller until the argument is ready and resumes when the
deferred computation is terminated (either successfully or unsuccessfully)
o It returns the resulting value or throws the corresponding exception if the
deferred was cancelled or did fail for any reason© G. Malnati, C. Barberis, 2012-23 82
Typical usage pattern
• Coroutines are usually created in a ViewModelScope or
LifecycleScope
o And can switch thread when performing I/O or CPU intensive operations
using withContext(…)
• Coroutine results can be modelled by a generic Result<T> class
o Encapsulating the data or an error
class Result<out T>(
val value: T?,
val throwable: Throwable?
)© G. Malnati, C. Barberis, 2012-23 84
Invoking the Repository
• Androidx viewmodel library introduces the viewModelScope
extension property that provides a dedicated CoroutineScope
o It can be used to launch coroutines from the ViewModel instance, all
having a SupervisorJob
o When the ViewModel is cleared, all pending coroutines are automatically
cancelled
o Dispatchers.Main is set as the default dispatcher© G. Malnati, C. Barberis, 2012-23 86
Coroutine summary
• The JVM does not provide native support for coroutines
• Kotlin implements coroutines in the compiler via transformation
of suspending functions into state machines
• Kotlin uses a single keyword for the implementation, the rest is
done in libraries
• Kotlin uses Continuation Passing Style (CPS) to implement
coroutines
• By using dispatchers, its easy to switch thread and keep the code
simple to read and maintain