Office Hours — Today, October 6

Thursday, October 4

Oct 6
3:55 PM
Mark M.
has entered the room
Mark M.
turned on guest access
4:00 PM
Jan
has entered the room
Mark M.
hello, Jan!
how can I help you today?
Jan
Hello, Mark! I would like to ask why should we use UUID as a primary key in the Room instead of int (autogenerated)?
Mark M.
"should" is a strong term -- I happen to use UUIDs, but that is not a requirement
Aaron
has entered the room
Mark M.
I prefer to know my primary key before the data is inserted into the database
4:05 PM
Jan
I understand. But what are the benefits?
Mark M.
well, one benefit is knowing the primary key before the data is inserted into the database
that makes it easier to set up relations ahead of time, for example
plus, it is more difficult to have immutable objects as your entities if you use an autogenerated primary key
you are absolutely welcome to use an autogenerated primary key if you wish
(BTW, hello Aaron -- I will be with you shortly!)
Aaron
hello, and np
Jan
Do you think there is any disadvantage using UUID?
Mark M.
I have not done performance testing, but it is possible that generating a UUID in Java is a bit slower than having SQLite assign an integer primary key
I expect that the difference will be dwarfed by the disk I/O time, though
UUIDs are bigger, both in memory and on disk, which is not great
so there are trade-offs that larger apps may wish to consider
let me take a question from Aaron, and I will be back with you shortly
Aaron: your turn! do you have a question?
Jan
Ok, no problem :)
4:10 PM
Aaron
yes, I am implementing data binding in my app and I have a couple questions about that. first,
I am planning to bind to LiveData directly. if I understand right, this eliminates the need for an Observer, correct?
Mark M.
correct
Aaron
ok, great, and the second part of this is,
my app is based around one big, many-layers-deep model object that contains all kinds of different variables, so I need to extract the ones I want to bind them to the correct views, and I am trying to determine the best way to do this. your book mentions @BindingConversion as one option. as far as I can tell, the other main option would be to manually split my mega-object LiveData into many smaller LiveDatas, each which contains the data for one view. am I correct in saying this is the primary alternative, and if so, can you say anything about the pros and cons of each?
Mark M.
in the phrase "each which contains the data for one view", what is your definition of "view"?
do you mean widget? do you mean activity/fragment? do you mean something else?
Aaron
widgets, mostly TextEdits
sorry
TextViews
*
Mark M.
having individual LiveData objects per widget seems excessive
4:15 PM
Mark M.
though I have seen people do that
4:15 PM
Mark M.
personally, I prefer to have a "viewstate" object that has the data needed by the layout, and have a LiveData<ViewState> that is used for the data binding
but there are lots of possibilities
basically, I like having atomic changes to my model data and its visual representation -- you'll see that philosophy in the MVI discussions in "Android's Architecture Components"
Aaron
hmm, OK, I need a moment to prepare my follow-up questions, so Jan, if you have more questions, please go ahead
Mark M.
not everything neatly fits that (e.g., exceptions), and so some things might wind up in separate LiveData objects
OK, Jan, back to you! do you have another question?
Jan
Hmmm, I am thinking about using Integer instead of int as a primary key. Is it possible? It will allow me to save null.
Mark M.
yes, and IIRC that is the recommended approach
though usually null is not a value that you would save for the primary key
4:20 PM
Mark M.
foreign key relations, though, might have null indication "no relation"
and null meaning "not yet inserted" is OK in a primary key role
Jan
You're right ... I have a little experience with databases.
I need to test it more. My app is not in production so no problem.
Thanks Mark for your answers. I have to go now.
Mark M.
you're welcome!
Aaron: back to you!
Jan
Bye for now.
Aaron
OK, so to make sure I understand, w/r/t the "viewstate", in that case, what you are doing is taking your BigModelObject and extracting out ONLY the data relevant to the layout, and putting all that into a new viewstate object wrapped by a LiveData? Probably by constructing it with a MutableLiveData?
Mark M.
JanL see you next time!
that's one possibility
if the view is only on a piece of the BigModelObject, and just handing the BigModelObject to the layout for data binding would be difficult/inconvenient/icky, then somewhere there is a conversion
Jan
has left the room
Mark M.
there are a few options for how you do that conversion and data bind it
I am assuming from context that somewhere you have a LiveData<BigModelObject>
am I correct in that assumption?
Aaron
please do summarize those options
yes
4:25 PM
Mark M.
one possibility would be Transformations.map()
this takes your LiveData<BigModelObject> and a lambda or Function that can convert BigModelObject into StuffNeededByYourLayout, giving you a LiveData<StuffNeededByYourLayout>
if your data binding has access to that LiveData<StuffNeededByYourLayout>, you can have binding expressions accessing fields or methods of StuffNeededByYourLayout
another possibility is that your activity/fragment observes the LiveData<BigModelObject> and then binds individual things onto your data binding
so, inside of the observe() lambda or Observer, you are calling methods on your data binding for various variables
this is more of pushing the changes into the data binding, rather than having the binding respond to reactive changes
4:30 PM
Mark M.
a variation on that theme is to have the observe() lambda/Observer populate 1+ MutableLiveData objects, which you have previously bound into the data binding
4:30 PM
Mark M.
another variation on that theme is that you have some object that is an MVVM-style viewmodel (not necessarily an Architecture Components ViewModel) that is Observable, and you data bind that into the layout, and your observe() lambda/Observer is updating that viewmodel
the first approach (Transformations.map()) is the simplest, if you can reasonably create a StuffNeededByYourLayout class
there are probably other approaches too that I'm not thinking of right now
4:35 PM
Aaron
OK that's an extremely helpful summary. I think in my particular case today, there is really no distinction between my model object and what is needed by my layout, as I'm not storing any state, just displaying the copypastas and cat pics of the hour from Reddit, so I will probably not bother to construct a separate viewstate object. but, the approach I would like to try in this app is what you identified here: "having the binding respond to reactive changes". Here is where I am getting stuck exactly:
(typing)
Mark M.
(waiting with breathless anticipation)
(**gasps**)
(now waiting and breathing again)
Aaron
let me know if I should call the ambulance
Mark M.
(wheeze) no, I'll (cough) be OK
4:40 PM
Aaron
View paste
OK, so this is the exact point where I'm getting stuck -> "you can have binding expressions accessing fields or methods of StuffNeededByYourLayout" I am just not sure HOW to bind directly to individual variables inside that LiveData<ViewState>. Like, I cannot do @{viewState.name} and @{viewState.age}...because that's not how you access fields inside an object wrapped by LiveData. You use getValue. but doing @{viewState.getValue(name)} cannot be right, because I want to continuously "observe", not pull out the value at a given point in time, which is what getValue does (right?) - I am just not sure what is needed. I know how to do it when I have an Observer in the code, but I am missing what is needed to "have the binding respond" directly and eliminate the observer. 

I've tried looking at sample apps from your book, and the closest thing I found was @BindingConversion, but I do not think that is right. If i understand, it is for converting one type of object to another, and is ALWAYS applied (as per documentation "Converters are used whenever they can be applied and are not specific to any attribute. ") 

I think it worked in your particular example because it was a simple app wit
...
Mark M.
let's say that your <variable> is a ViewModel named vm
Aaron
ok
Mark M.
and let's say that the ViewModel has a field named stuff that is a LiveData<StuffNeededByYourLayout>
Aaron
ok
Mark M.
and let's say that StuffNeededByYourLayout has a field name title
that you want to bind into a TextView
Aaron
ok
Mark M.
your android:text binding expression would be @{vm.stuff.title}
vm is the variable
stuff is the LiveData in vm
Aaron
D:
is it really that simple
oy
Mark M.
data binding then realizes that this is a LiveData, so it sets up an Observer for stuff
4:45 PM
Mark M.
yes
4:45 PM
Mark M.
I haven't written about it yet, but I've been using it on a project over the past few months
it's pretty slick
Aaron
I mean... it doesn't work that way in java, right? Or am I wrong about that too
Mark M.
no, Java is more complex than that
even Kotlin is more complex than that
but, it's a logical extension of how they handle Observable fields
suppose vm is the ViewModel, stuff is an Observable<StuffNeededByYourLayout>, and title is a field in StuffNeededByYourLayout
Aaron
yes, that is very good, and I am pleasantly surprised
Mark M.
your binding expression is the same: @{vm.stuff.title}
Aaron
I searched for many examples of Livedata with data binding online, in addition to reading and re-reading your book, and nowhere did I find any examples working like this. I did not even bother to try myself as I just assumed it would not work.
but that is great
Mark M.
first, it's pretty new -- I think it debuted with AS 3.1 and the related tools
and Google hasn't really talked about it much
but yes, it's one of those things that I need to write up someday
before I forget, some more notes that I typed up earlier (while waiting on Jan):
the biggest downside that I have run into is that data binding does not seem to like generics -- I have had no luck in declaring a variable of LiveData<Foo>
however, if your variable is something else (e.g., a ViewModel) that happens to hold a LiveData<Foo>, that works quite nicely
Aaron
hmm, ok
Mark M.
that's why, in the examples that I wrote just above, I have the <variable> be a ViewModel
Aaron
got it
4:50 PM
Mark M.
it does not have to be a ViewModel, but it has to have fields/methods that have your LiveData, rather than trying to bind the LiveData in directly
Aaron
OK
Mark M.
alternatively, if you are creating your own LiveData subclasses, those are fine to bind in
it's the angle brackets in the generic declaration that screw up LiveData<Foo>
because we're in XML, and angle brackets have particular meaning there
I forget if I tried LiveData&lt;Foo&gt;, but that's just ugly
Aaron
ok, good tip
please continue if you have any other notes (I really wish this chat had a typing indicator), but I have one more question to hopefully address in the time remaining
Mark M.
no, that was it
Aaron
I would like to ask this in a more granular way, but I did not have time to properly research beforehand, so sorry about that,
but i am a bit fuzzy on MutableLiveData vs. MediatorLiveData vs. Transformations (particularly the last two)
I am not sure exactly where these overlap in purpose and differ
if you could provide a high level summary in the next five minutes to point me in the right direction to reserach further, that would be great
Mark M.
Transformations has two static methods: map() and switchMap()
IIRC, if you look at their implementation, you will see that they use a MediatorLiveData under the covers
4:55 PM
Mark M.
from what I can tell, MediatorLiveData is there to do the "heavy lifting" behind those sorts of transformation methods
in my "LiveData Transformations" chapter of "Android's Architecture Components", I work through an example of this
I create a filter() method that works like map() and switchMap(), but instead of converting performs a filter (only emitting objects that match certain criteria provided by a function)
MediatorLiveData can also be used if you have multiple/changing LiveData sources but want a stable LiveData that can be used by a consumer
I work through an example of that in the "LiveData and Data Binding" chapter
in the context of your app, suppose that you had a search screen, with a search field and a RecyclerView of search results
if the user already has done a search, and types in a separate search and submits it, you decide that you want to keep the user on this same screen, rather than creating a new fragment to show the new search results
however, you are already using the LiveData from your previous search request, and it may be inconvenient for you to swap in some other Livedata
so, instead of your fragment using the search result LiveData directly, you have it observe a MediatorLiveData, probably managed by your ViewModel
5:00 PM
Aaron
I see
5:00 PM
Mark M.
when a search is done, the LiveData of search results is attached to the MediatorLiveData, and the old search results are detached
now your fragment has a single MediatorLiveData that it observes all the time
but it still gets the new data sets based on a search
Aaron
ok, thanks for the info, let me not keep you past the hour, I will look into these examples and ask more questions later if needed
Mark M.
so, those are two uses of MediatorLiveData that I know of
OK
the next chat is Tuesday at 9am US Eastern
Aaron
btw, I just noticed a typo on p.171 of architecture book, last paragraph, "that return" -> "that returns"
ok great
thanks!
Mark M.
OK, I'll get that fixed
Aaron
enjoy the rest of the weekend
Mark M.
BTW, I assume you had no problems getting into the new site, since you're here :-)
Aaron
yes
I'll let you know if I have any feedback on it, haven't really looked closely yet
Mark M.
thanks!
Aaron
but it worked well enough to get me here
talk later!
Aaron
has left the room
Mark M.
turned off guest access

Thursday, October 4

 

Office Hours

People in this transcript

  • Aaron
  • Jan
  • Mark Murphy