Office Hours — Today, March 27

Thursday, March 25

Mar 27
3:50 PM
Mark M.
has entered the room
Mark M.
turned on guest access
4:00 PM
Eric
has entered the room
Mark M.
hello, Eric! how can I help you today?
Eric
Mark!
I want to get clarification. We are not supposed to make network calls on our main thread because it will slow UI animations. It sounds like it is possible to make a network request on a main thread but NetworkOnMainThreadException exists and it seems to say you can't
4:05 PM
Mark M.
beyond animations, it totally freezes your UI
Eric
it sounds like you are confirming it is possible, but is a blocking operation. So I am confused because NetworkOnMainThreadException is defined as an exception thrown if you ATTEMPT to make network requests on the main therad
Mark M.
correct, that is thrown by StrictMode when it detects an attempt to do network I/O on the main application thread
Eric
I see, so it won't crash the app but slows it instead?
actually can it crash an app?
Mark M.
NetworkOnMainThreadException crashes the app, unless you handle the exception
4:10 PM
Mark M.
so, by default, network I/O on the main application thread crashes the app, unless you handle the exception
Eric
ok, so if it crashed why do people say it blocks your UI and slows it down?
Mark M.
for two reasons
1. that is what the behavior was before Android 4.0
2. that is the behavior if you disable StrictMode's check for network I/O on the main application thread
it's 2021, and we have tons of ways of doing network I/O on background threads
Eric
ok if I enable strictmode to see if network I/O is done on the main thread will it crash?
Mark M.
it will throw NetworkOnMainThreadException, which if you do not handle the exception will cause you to crash
4:15 PM
Eric
I am reading elements of coroutines. You mention we don't want to make network requests on the ui thread to prevent blocking it. Are you assuming a disabled strictmode check, because otherwise wouldn't it crash(assujming you don't catch the eception)
Mark M.
ah, I should improve that phrasing
but, yes, I am assuming a disabled StrictMode check
Eric
View paste
cool.  If I have this coroutine:
launch(Dispatchers.io()) {
    val result = networkCall() // line A
    val str = "My name is $result.name" // line B
}
Would it be accurate to say line A is a blocking call in Dispatchers.io()?
because str depends on the result of networkCall
Mark M.
that depends on whether or not networkCall() has the suspend keyword
4:20 PM
Eric
yes networkCall() is a suspend function
Mark M.
then, technically, networkCall() is not a blocking call, but through coroutines, line B will not be executed until line A returns
Eric
I'm struggling to understand what is meant by a suspend function suspends execution but does not block it, because line B relies on line A
Mark M.
well, it depends a lot on how you use "block" as a verb
Eric
totally
Mark M.
when I think of the phrase "blocking call", I think that it is going to tie up the current thread of execution
however, Dispatchers.io() wraps a thread pool, not a single thread
so, we enter your coroutine, and we are running on Thread IO-1
Kotlin sees the networkCall() invocation, and sees that it is a suspend function
depending on what else is going on, Kotlin may not execute networkCall() right away
and, whenever Kotlin gets around to executing networkCall(), the *body* of networkCall() (the function implementation) might be executed on thread IO-2
4:25 PM
Mark M.
the original portion of the coroutine (your launch() and line A and line B) is suspended until networkCall() completes and returns
once that happens, line B can be executed, and AFAIK that could be on any Dispatchers.io() thread (IO-1, IO-2, IO-3, ...)
now, suppose you use the backspace key and remove the suspend keyword from the networkCall() declaration
at this point, networkCall() is a blocking call, from the standpoint of this coroutine, because we cannot suspend execution of the coroutine
so, if we start the coroutine on thread IO-1, networkCall() will be called on IO-1, and line B will be executed on IO-1
(networkCall() could do its own coroutine or other threading stuff inside its implementation, and I am ignoring that in this discussion)
Eric
if I remove the suspend keyword won't I get an error saying networkCall() must be called within a coroutine or suspend function? I think I saw that?
Mark M.
no
now, you might get complaints from the *implementation* of networkCall(), if you are calling suspend functions in there
4:35 PM
Eric
View paste (1 more line)
ok.  When you say "depending on what else is going on, Kotlin may not execute networkCall() right away", is this why in your example

fun main() { GlobalScope.launch(Dispatchers.Main) {
    println("This is executed before the first delay") // line A
    stallForTime() // line B
    println("This is executed after the first delay") // line C
}
  GlobalScope.launch(Dispatchers.Main) {
    println("This is executed before the second delay") // line D
    stallForTime() // line E
    println("This is executed after the second delay") // line F
}
  println("This is executed immediately") // line E
}

...
Mark M.
I would phrase it more as: either line A or line D could be executed first
Dispatchers.Main usually has a single thread, whatever the framework's "main application thread" is, which varies by environment
and how a dispatcher decides which of two available coroutines to run is up to the implementation of the dispatcher, and for Dispatchers.Main in particular, that will vary by environment
so, how the Klassbook behaves using Kotlin/JS may be different than how Android behaves using Kotlin/JVM and a Dispatchers.Main that is tied to the Android main application thread
since stallForTime() is a suspend function, when either line B or line E is reached, the dispatcher could elect to switch execution to the other coroutine, if it is ready to run
Eric
is it possible coroutine 1 completes before coroutine 2 starts then?
Mark M.
theoretically, but very unlikely, given that stallForTime() stalls for time
4:40 PM
Mark M.
once we get to line B, the first coroutine will be delaying, and so Dispatchers.Main should start work on the second coroutine, since it is ready to run
4:45 PM
Eric
ok I'll need to play around withthis some more. Final question unrelated to coroutines actually. Is there a way to shorten this statement: if (author.book == null) { // lines of code } else print(author.book.title)
Mark M.
probably not
Eric
I appreciate it mark, bye!
Mark M.
happy to help!
Eric
:)
til next time then
Eric
has left the room
5:00 PM
Mark M.
turned off guest access

Thursday, March 25

 

Office Hours

People in this transcript

  • Eric
  • Mark Murphy