Office Hours — Today, July 25

Tuesday, July 23

Mark M.
has entered the room
Jul 25
3:55 PM
Mark M.
turned on guest access
4:00 PM
Erik
has entered the room
Erik
hi mark
Mark M.
hello, Erik!
how can I help you today?
Erik
have you seen a junit test pass but fail when run in a suite?
Mark M.
no, but I don't use suites all that much
is this a unit test or an instrumented test?
Erik
i am getting inconsistent test results when running a file containing junit tests
they all pass individually but some fail soetimes
Mark M.
I happened to be looking at the source code to Suite not that long ago -- it seemed like it just creates runners for the tests in the suite and executes them
Erik
it does not subscribe to the Single. I am using Rx
Mark M.
sorry, but I do not know what "it" is in "it does not subscribe to the Single"
4:05 PM
Erik
sorry
Mark M.
back, back to Suite... while I cannot rule out Suite being a problem, I would be a bit surprised
Erik
the reason the test fails is because I try to verify something inside the onSuccess callback of a Single in rx
it appears that callback is not invoked when I run the file
it works if I run the test by itself however
Mark M.
particularly since we are talking about Rx, this feels like the classic "it's a timing thing"
are you using TestScheduler? or how are you triggering the Single to process?
4:10 PM
Erik
doReturn(Single.just(20)).whenever(vendingMachine).getInventory(COKE). in the function that is being tested, I subsribe on the io thread and observe on main
Mark M.
I do not recommend using "real" schedulers in tests
use Schedulers.io and AndroidSchedulers.mainThread for production code
Erik
I use Schedulers.trampoline
Mark M.
ah, OK, that's a better choice
it also should eliminate my timing concern
Erik
Mark M.
however, I do not know why using a JUnit Suite would affect the behavior of your Single
Erik
maybe it isnt
Mark M.
I have not needed to write tests for RxJava-based code in a year
Erik
oh alright. can I ask you a different question
Mark M.
I recall it being kinda painful until we had a reliable recipe going, then it was fairly stable
Erik
yeah
Mark M.
though we did not use Suite
4:15 PM
Erik
this question is regarding exceptions. in an app should i catch unchecked exceptions like indexoutofbounds?
Mark M.
only if you know of a specific scenario where it might get thrown, and you want to handle it with your own app logic
otherwise, I would handle it however you are handling unexpected exceptions (e.g., crash logging)
Erik
if the exception were only to occur due to bad code would you catch it or let it crash to let the developer know the error? I hear one opinion that says it is not good to crash and another that says you want the logical error obvious.
Mark M.
in an ideal world, our apps would not crash
in an ideal world, I would have a full head of hair
this is not an ideal world :-(
4:20 PM
Mark M.
however, suppose you put a try/catch block around the code, and you specifically catch an IndedOutOfBoundsException... now what?
you need to show some sort of "oops!" message to the user, and you need to let developers know that this sort of thing can happen, such as with a stack trace
you need to do those things for unexpected exceptions too
Erik
you prevent the crash by not executing a block of code, so you dont crash. BUT you also may not see the error, such as if that code were to otherwise render a block of text
Mark M.
if the exception is known to be harmless, and you want to catch the exception to ignore it, that's fine... but you need to be sure that it is harmless
and for harmless exceptions, you may not need to alert the developers of the problem
I cannot say whether your specific IndexOutOfRangeException is harmless or not
my general point is: do not feel that you have to try to read through the source code for the Android SDK and libraries, to see what possible runtime exceptions there are, and try to set up catch blocks for each of them
after all, once you move to Kotlin, *everything* is a runtime exception
as Kotlin does not support checked exceptions
4:25 PM
Erik
OK. A related question is with the non-safe(!!) operator in kotlin. Say I have a listener. I will assign the listener to a non-null value. when I exit the screen I null it out. Should this listener do listener!!.onMessageReceived() or listener?.onMessageReceived()?
Mark M.
off the cuff, my answer would be: do not null it out
make sure that the object with this listener properly will be garbage-collected in a reasonable timeframe, without making the listener property be nullable
if there is a specific scenario where you do not control the lifetime of the object with the listener property, and you that you need to null it out... I would use ?. instead of !!
4:30 PM
Mark M.
but the overall Kotlin philosophy is to use null sparingly
Erik
listener outlives the fragment. if i dont null out the fragment i thought there would be a memory leak when the fragment is dead
sorry
Mark M.
I do not know enough about your object model to be able to answer that
Erik
listener is the activity but defined in fragment. once the fragment is popped I null the listener so I do not leak the activity that is still available.
Mark M.
there are probably better patterns to use here, such as a shared ViewModel with LiveData
however, the fragment will not outlive the activity, so it is fine if the fragment points to the activity
assuming an ordinary non-retained fragment
Erik
this pattern is also recommended by google for inter-fragment communication; yes the fragment will not outlive the activity but the listener defined in the fragment IS the activity and that outlives the fragment of course.
4:35 PM
Mark M.
but that just means that the fragment is holding onto a reference to the activity
if the activity held a reference to the fragment, and the fragment was destroyed, that would be a memory leak
if the fragment held a reference to the activity, and the fragment was destroyed, there is no memory leak
Erik
you dont leak the activity since that is the listener defined in the fragment itself
Mark M.
the fact that the activity is serving in the role of a listener here does not really matter
Erik
doesnt a leak occur anytime you hold onto something longer than it can be used
Mark M.
no
short-lived objects pointing to long-lived objects is not a problem
long-lived objects pointing to what should be short-lived objects is a problem
in your scenario, once the fragment is destroyed, the activity will release its reference to the fragment
at that point, assuming that nothing else points to the fragment, the garbage collector can collect the fragment
it does not matter whether the fragment points to the activity -- if nothing points to the fragment, the fragment can be garbage-collected
4:40 PM
Erik
oh thanks. I saw sample code where someone set their listeners to null when leaving the screen to try and prevent a memory leak
Mark M.
there may be scenarios where that is needed -- yours does not appear to be one of them
Erik
the classic example of a memory leak is an asynctask declared anonymously. it holds a reference to the outer activity. what is the long lived object in this scenario and the short lived object
Mark M.
to an extent, that depends on what the AsyncTask does
Erik
network request
Mark M.
that could be short or that could be long
Erik
why does that matter
Mark M.
you asked which is the long-lived object and which is the short-lived object
the answer in this case is: it depends on what the user does and what the network does
4:45 PM
Erik
fetches a url
Mark M.
but, this is why an AsyncTask really needs to be a static inner class or a regular class, not an anonymous inner class
and, this is why an AsyncTask needs to be managed by a retained fragment
which is why AsyncTask is no longer a particularly good option, since it is tricky to implement without introducing possible memory leaks
Erik
yeah im trying to make sense of your explanation. I learned the leak occurs because it takes time to fetch the url and if you rotate the screen the activity is destroyed. You have a task that outlives the activity and the leak is the activity
Mark M.
correct
however, if the network request is short, and the user does not rotate the activity or otherwise destroy it, then the activity is the long-lived object, compared to the AsyncTask
from a programming standpoint, we need to consider the worst-case scenario, which usually is a slow network
Erik
correct.
Mark M.
and that's why an anonymous inner class AsyncTask is not recommended
4:50 PM
Mark M.
in the case of activities and fragments, the lifetimes are better known in relation to one another
Erik
isnt that true for anon inner classes in general though? They all hold references to the outer class. Most of the android code out there uses anon inner classes for listeners though
Mark M.
so long as the listener does not outlive the activity, it is OK
so, a View.OnClickListener is fine as an anonymous inner class
the problem is that the AsyncTask is not only held onto by the activity, but also by the Thread that is doing the background work
and that Thread will reference the AsyncTask until the task is completed
nothing other than the activity and its views should be referencing the View.OnClickListener, so the listener is not a risk of causing a memory leak
Erik
can you recommend a tool to detect leaks that is easy to understand
Mark M.
LeakCanary
Erik
yeah some of those traces weree hard to understand
Mark M.
that's unavoidable
all a leak detector can do is point out that there appears to be a leak
*why* you have the leak is a far more difficult problem to solve
Erik
wtf is a zygote
Mark M.
do you mean in Android or in biology? :-)
Erik
leakcanary leak traces show that and it is hard to understand the source of the problem
Mark M.
hmmm... it has been a while since I looked at a LeakCanary trace, but I do not remember it referencing the zygote
4:55 PM
Mark M.
regardless, in Android, the zygote is the process from which all Android apps' processes is forked
Erik
thanks for your help mark
bye
Mark M.
you're welcome!
Erik
has left the room
5:00 PM
Mark M.
turned off guest access

Tuesday, July 23

 

Office Hours

People in this transcript

  • Erik
  • Mark Murphy