Mark M. | has entered the room |
Jul 25 | 3:55 PM |
Mark M. | turned on guest access |
Jul 25 | 4:00 PM |
Erik | has entered the room |
Erik |
hi mark
|
Mark M. |
hello, Erik!
|
Mark M. |
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
|
Mark M. |
is this a unit test or an instrumented test?
|
Erik |
i am getting inconsistent test results when running a file containing junit tests
|
Erik |
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"
|
Jul 25 | 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
|
Erik |
it appears that callback is not invoked when I run the file
|
Erik |
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"
|
Mark M. |
are you using TestScheduler? or how are you triggering the Single to process?
|
Jul 25 | 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
|
Mark M. |
use Schedulers.io and AndroidSchedulers.mainThread for production code
|
Erik |
I use Schedulers.trampoline
|
Mark M. |
ah, OK, that's a better choice
|
Mark M. |
it also should eliminate my timing concern
|
Erik |
yeah I followed this post https://medium.com/@peter.tackage/overriding-rx...
|
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
|
Jul 25 | 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
|
Mark M. |
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
|
Mark M. |
in an ideal world, I would have a full head of hair
|
Mark M. |
this is not an ideal world :-(
|
Jul 25 | 4:20 PM |
Mark M. |
however, suppose you put a try/catch block around the code, and you specifically catch an IndedOutOfBoundsException... now what?
|
Mark M. |
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
|
Mark M. |
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
|
Mark M. |
and for harmless exceptions, you may not need to alert the developers of the problem
|
Mark M. |
I cannot say whether your specific IndexOutOfRangeException is harmless or not
|
Mark M. |
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
|
Mark M. |
after all, once you move to Kotlin, *everything* is a runtime exception
|
Mark M. |
as Kotlin does not support checked exceptions
|
Jul 25 | 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
|
Mark M. |
make sure that the object with this listener properly will be garbage-collected in a reasonable timeframe, without making the listener property be nullable
|
Mark M. |
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 !!
|
Jul 25 | 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
|
Erik |
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
|
Mark M. |
however, the fragment will not outlive the activity, so it is fine if the fragment points to the activity
|
Mark M. |
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.
|
Jul 25 | 4:35 PM |
Mark M. |
but that just means that the fragment is holding onto a reference to the activity
|
Mark M. |
if the activity held a reference to the fragment, and the fragment was destroyed, that would be a memory leak
|
Mark M. |
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
|
Mark M. |
short-lived objects pointing to long-lived objects is not a problem
|
Mark M. |
long-lived objects pointing to what should be short-lived objects is a problem
|
Mark M. |
in your scenario, once the fragment is destroyed, the activity will release its reference to the fragment
|
Mark M. |
at that point, assuming that nothing else points to the fragment, the garbage collector can collect the fragment
|
Mark M. |
it does not matter whether the fragment points to the activity -- if nothing points to the fragment, the fragment can be garbage-collected
|
Jul 25 | 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
|
Mark M. |
the answer in this case is: it depends on what the user does and what the network does
|
Jul 25 | 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
|
Mark M. |
and, this is why an AsyncTask needs to be managed by a retained fragment
|
Mark M. |
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
|
Mark M. |
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
|
Mark M. |
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
|
Jul 25 | 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
|
Mark M. |
so, a View.OnClickListener is fine as an anonymous inner class
|
Mark M. |
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
|
Mark M. |
and that Thread will reference the AsyncTask until the task is completed
|
Mark M. |
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
|
Mark M. | |
Erik |
yeah some of those traces weree hard to understand
|
Mark M. |
that's unavoidable
|
Mark M. |
all a leak detector can do is point out that there appears to be a leak
|
Mark M. |
*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
|
Jul 25 | 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
|
Erik |
bye
|
Mark M. |
you're welcome!
|
Erik | has left the room |
Jul 25 | 5:00 PM |
Mark M. | turned off guest access |