Office Hours — Today, November 27

Wednesday, November 21

Nov 27
7:20 PM
Mark M.
has entered the room
Mark M.
turned on guest access
7:30 PM
Aaron
has entered the room
Mark M.
hello, Aaron!
how can I help you today?
7:35 PM
Aaron
hey Mark, today I have two questions, trying to understand some aspects of memory management better
here they are:
View paste (36 more lines)
1. Say you have a fragment that is going to be frequently replace()'d, and thus come & go from the backstack. It has a LiveData observer which operates on some view in its view hierarchy. So, the observer is registered in onCreateView() or onActivityCreated() and uses getViewLifecycleOwner() as the LifecycleOwner to avoid leaking observers when the fragment goes on the backstack and is detached but not destroyed. For example:
 
 ```
    private void setupMyObserver() {
        viewModel.getXyzLiveData().observe(getViewLifecycleOwner(), xyz -> {
            getView().findViewById(R.id.my_view) .setVisibility(View.VISIBLE);
        });
    }
```

In this case, the only reference being kept to the lambda, and therefore to the view it references, would be the reference held by the LiveData due to the observe() call. i.e., neither the fragment itself nor any other objects EXCEPT the LiveData would hold onto the lambda, therefore, this setup should be completely sufficient to avoid leaking either observers or views when the fragment comes and goes from the backstack. Is that all correct, or is there still some potential to leak the view in this scenario?

2. Possibly related: do all 3 of
...
code pasted a little sloppier than it looked in my editor, sorry about that
Mark M.
yeah, this chat doesn't support Markdown
Aaron
yeah, not just that, also weird space problems
Mark M.
for #1, "Is that all correct, or is there still some potential to leak the view in this scenario?" -- I think you're fine, though I can't be 100% certain
Aaron
ok, right, but if it's OK based just on what I described there, that is good to know
Mark M.
for #2, b) is distinctly different
7:40 PM
Mark M.
I would worry about the lambda having a reference to the view in that case
Seven
has entered the room
Mark M.
a) and c) would be my preferred options
(BTW, hello Seven -- I will be with you shortly!)
Seven
Hi, I just bought the book subscription and saw there was an active office hours.
Mark M.
yup! I run these usually three times a week -- the calendar is there on the Warescription site
Aaron
ok, so first question would be, isn't a) essentially just accessing a field with a getter method w/ getView()? I thought a) and b) were similar but c) might be different
Mark M.
in your scenario a), though, the lambda itself does not have a reference to the field
whereas in b) it does, and that is what worries me
a) is really no different than c), other than in the particular methods that you are calling
Seven
ah ok, that's cool :)
Mark M.
let me take a question from Seven, and I'll be back with you shortly
7:45 PM
Mark M.
Seven: I tend to go round-robin between the participants, so everyone has a chance and I'm not trying to juggle multiple chat threads at once
so... your turn! do you have a question?
Seven
Aah nice, yes I have one
I am kind of new to Room and RxJava
I am trying to make a query to just get the count of entries in one table and I think I may be able to use RxJava's Single to make that query
View paste
Something like this:
@Query("SELECT COUNT(*) FROM transfers")
fun getCount(): Single<Int>
Mark M.
it might need to be a Long, but otherwise that looks good
Seven
Ok, and how would I call it from my code?
Mark M.
well, that function would be on an interface or abstract class annotated with @Dao
Seven
Ah yeah, I have that one
Mark M.
and you get an instance of that DAO from your RoomDatabase subclass, via an abstract function on it
Seven
But I was migrating from SQLHelper to Room
View paste
And I had this call from an activity:
val transferCount = transferRepository!!.getCount()
7:50 PM
Mark M.
your repository can wrap your RoomDatabase and hide the implementation details from the rest of the app
Seven
Now that call throws an error, I cannot access the db on the main thread
Mark M.
right, Room does not like that
but that is where your Single comes into play
your repository can make the Single available, and your GUI code (e.g., a viewmodel) can subscribe() to the Single
or, you can use LiveDataReactiveStreams to convert the Single into a LiveData, that you can observe
Seven
Cool, I think I may find an example of that in your book
Mark M.
both of those would allow the actual database I/O to occur on a background thread, but let you get the results on the main application thread
yes, I have a few examples that show this approach
in "Android's Architecture Components", one of the books in your subscription
Seven
Yeah, I saw an intro of that book and decided to buy the whole subscription
Mark M.
thanks! :-)
Seven
I saw that there is an example that uses Single
Thanks!!
This office hours are great, did not know I would have that when buying the book
You can answer Aaron questions :)
I will come prepared with more structured questions next time
Mark M.
OK, I will swing back to you in a bit
sounds good!
Aaron: your turn! do you have another question?
Aaron
yes, just a couple quick follow-ups then I'm done,
in response to your last message:
yes, that makes sense about a) and c). so, it's basically like, a lambda that calls a getter doesn't risk leaking the view because it would only hold a reference to the view in whatever local scope exists at the time the lambda is executed, whereas a lambda like b) keeps the reference from the time the lambda is created and passed to the observer, until it leaves memory. accurate? I read several pieces about variable capture but none of them really went into this distinction (because it's just that obvious, I guess)
Mark M.
your explanation matches my understanding
7:55 PM
Mark M.
in the end, a lambda is an instance of an anonymous inner class, just with simpler syntax
Aaron
yeah, ok, good
last question,
if you are using an AIC for an observer and you want to manually unregister it, you can keep a reference to it, for example in some final member variable - if you are using a lambda instead of an AIC, then it should be possible to do a similar thing, by virtue of lambdas supporting variable initialization as a target type context, right?
i.e., assign the lambda to a variable and then pass the variable to the observer?
Mark M.
I haven't tried that in Java, but I agree that it should work
Aaron
ok, thanks
Mark M.
View paste
you should be able to have:

View.OnClickListener clickyClicky = { v -> doStuff(); }
Aaron
yep, OK
that's all I've got, thanks again and have a good night!
Mark M.
you too!
Aaron
has left the room
Mark M.
Seven: back to you -- do you have another question?
8:00 PM
Seven
Yes kind of
I am seeing the book on to how to use RxJava's Single
It provides an example of how to use single in the DAO
But I do not know what syntax would be used in my Repository
Mark M.
*in* the repository would be just calling the getCount() function on your DAO
View paste
so, if your repository has a roomDb property that is your RoomDatabase, you could have this in the repository:

fun getCount() = roomDb.yourDao.getCount()
(actually, that would be roomDb.yourDao().getCount())
where things get more complicated is in the *client* of the repository
Seven
Ah ok, I have that now
yeah yea
I need to use some kind of subscription iirc
Mark M.
right
what I tend to lean towards is to use LiveDataReactiveStreams in my viewmodel
so my viewmodel would call getCount() on the repository, then use LiveDataReactiveStreams to convert that into a LiveData, which it exposes to the activity or fragment
the activity or fragment can then observe() that LiveData, or pass it to the layout via data binding
8:05 PM
Seven
ah ok, well I do not need to make something that complicated I think
Not in this specific scenario
Mark M.
well, if you go this route, you do not need to worry about cleaning up the RxJava subscription, as LiveData handles that for you as part of its lifecycle management logic
Seven
How much time do we have left?
Mark M.
if you want to skip the LiveData, that's fine -- you just need to remember to dispose() your subscription and arrange to observe on the main application thread
the chat wraps at 8:30pm US Eastern -- so, ~24 minutes
Seven
Ah ok, I just did not want to take more time than what you were offering
Ok, I think I am having a revelation now lol
I will try to just explain what I thought and please tell me what you think about it
Mark M.
OK
Seven
I think I still was thinking in the old way, I have this call to the db to get the count of items and only proceed in one way if I have zero items and in other way otherwise.
8:10 PM
Seven
But instead of calling the database and wait for the result I could wrap all the necessary info into a viewmodel and have that information at my disposal for whenever I need it
Mark M.
yes
though not if you use Single
that is a one-time event
Seven
Exactly
Mark M.
if you want to know what the count is at a certain point in time, you request and subscribe to the Single
with Room, if you use Observable instead of Single, you would get a stream of counts, every time the table gets modified
Seven
Correct
Mark M.
so, you can choose which approach better fits your requirements
Seven
hmmm interesting
Mark M.
but beyond that, yes, your viewmodel handles most of the "dirty work"
Seven
Ok, I think that's it for now. I should be able to find out how to subscribe to the Single
Mark M.
in terms of subscribing, Single and Observable look pretty much the same
so any of my examples that show Observable should work the same if you used Single, with the only difference being how many events you might get
8:15 PM
Mark M.
IOW, don't limit yourself to Single examples
Seven
Of course, I will check the whole book
Thanks a lot
Mark M.
you're welcome!
BTW, these chat transcripts get posted at https://commonsware.com/office-hours/
this chat will be added shortly after it ends
Seven
ah ok did not know that
Have a good night!
Mark M.
you too!
Seven
has left the room
8:30 PM
Mark M.
turned off guest access

Wednesday, November 21

 

Office Hours

People in this transcript

  • Aaron
  • Mark Murphy
  • Seven