Office Hours — Today, May 15

Thursday, May 9

May 15
3:50 PM
Mark M.
has entered the room
3:55 PM
Mark M.
turned on guest access
4:00 PM
Anshul V.
has entered the room
Anshul V.
Hi Mark, how are you doing today?
Mark M.
hello, Anshul!
how can I help you today?
(and I'm doing well, thanks -- and you?)
Anshul V.
I am doing good, thanks. Let me try to explain a project I am working on currently..
4:05 PM
Anshul V.
View paste
I have a nested recycler view,
Parent - horizontal -> corresponding ParentViewModel
Child - vertical

Each child contains 2 types of viewholders
- Question (ImageView with textView) -> corresponding QViewModel
- Answer (radioButtons with TextViews) -> corresponding AViewModel

Now question is one, but answers are many!
I am trying to set an onClickListener() on the AnswerType which would let me get the answerId of the user selected answer, as well as mark the radio button in the answer.
I am using data binding with all these viewmodels as binding variables but it isn’t clear to me, how do I propagate the clicked answer back to the parent view model?
Mark M.
I guess that I am confused by all of the viewmodels
you can bind a click listener via data binding and android:onClick, and it can call methods on whatever you are binding, such as AViewModel
Anshul V.
I see, well, the child view models (QViewModel) and (AViewModel) are extended from the ParentViewModel, basically I have 1 viewmodel for parent adapter and 2 viewmodels for child recycler adapter
Mark M.
"extended" meaning inheritance?
Anshul V.
yes
Mark M.
OK, that's even more confusing than what I had been thinking which was that this was using composition
4:10 PM
Mark M.
anyway, not knowing much more about your code, you could always bind more things to the layout for the answers
Anshul V.
Ah, okay, so ParentViewModel receives a List<QuestionAnswerPairs> from the server, as a LiveData, the activity observes that LiveData<> and sets the ParentAdapter, which in turn sets the ChildAdapter in the onBindViewHolder()
Mark M.
that seems reasonable, at least on the surface
so, you could have the answer ViewHolder (or ChildAdapter, depending on your setup) bind both AViewModel and ParentViewModel into the row layout
then, your android:onClick could call a method on ParentViewModel to report the click event
Anshul V.
yeah, and the QViewModel and AViewModel are just trying to set the data to the layouts, and have any click listeners as you just mentioned
Oh, I see, so technically, I can receive the answerClickEvent directly in the ParentViewModel?
Mark M.
sure, if you wanted
it's just another <variable>
and a tweak to the binding expression
now, there may be architectural issues with doing this, if you want the child stuff to not know about the parent stuff
in that case, you might have the parent supply an OnClickListener, or a lambda expression, that the child can call to forward events to the parent
Anshul V.
Oh, the child view model would implement that listener and pass on the data to the parent view model..
4:15 PM
Mark M.
yes
so, either have the binding expression call a method on the parent view model directly, or have it call a method on the child view model, which in turn calls something to alert the parent
or, have the binding expression call a method on the child, which uses LiveData to inform the parent
there are a variety of options here
Anshul V.
That makes sense, okay, so where does the activity which hosts the Recyclerviews gets involved in this? Is it just setting the LiveData<List<QuestionAnswer>> to the Recycler view adapter? the rest is communication between VM <-> Adapters?
Mark M.
personally, I tend to have the activity/fragment be the LiveData observer and just pass the data to the adapter
your approach should work; I just haven't done it that way
Anshul V.
okay, that works! Now there's a twist in the tale, whatever number of questionAnswers the server sends us, we only display 1 QuestionAnswer in the RecyclerView in the beginning, once the user answers the first question, we load the second question. I guess that changes how we set the adapter from the LiveData, right?
4:20 PM
Mark M.
is this simply a display thing? or is the identity of the second question not known until the user answers the first question?
Anshul V.
both! the server sends batches of question, it can be one quesionAnswer batch, or 3. In the prior case, if only 1 question is sent, we display that to user, and once user answers it, we send the metadata back to the server to determine the next question/questionBatch
in latter, we display 1 question, user answers and we display another question, and then the 3rd question, before adding all the answers metadata to the request and send to server to receive next batch of questions
Mark M.
it would be nice if your view model could hide some of those differences from the UI layer
ideally, the view model would say "this is what you should be showing now" and that's it
the view model, in conjunction with the repository (or wherever your server API calls are happening), would determine what the "should be showing now" actually should be based on user input and server responses
4:25 PM
Anshul V.
So, Parent view model sends 1 question livedata to activity, which in turn sets the adapter, once the VM receives the first onClickAnswer event back, it stores it, either makes the api call, or append the second question to the livedata to activity, and the adapter gets initialized again, but now with 2 questions?
Mark M.
yes, given your UI setup
off the cuff, I am not a huge fan of the horizontal RecyclerView as the outer container -- I would prefer the questions be individual fragments with traditional navigation
Anshul V.
okay, makes sense! Can I be excused for a few moments?
Mark M.
but, I'm not the designer, and there may be solid reasons for your setup, even if it makes the work more difficult
and you are welcome to do whatever you want!
Anshul V.
okay, be right back
Mark M.
I'm not going anywhere for (...checks watch...) 33 minutes!
4:35 PM
Anshul V.
Haha.. I am back. Question, how do I make sure that the user can't select multiple answers at once? It should always be only 1 out of 4 answers
Mark M.
well, ideally, the four RadioButtons would be in a RadioGroup
I am not completely certain why the question and answers are implemented as a RecyclerView
but, if you want to stick with that, you would need to update all of the RadioButton objects for the correct checked/unchecked state
Anshul V.
Hehe, I have my doubts about that as well, we don't really know how many answers there might be in a question, may be 4, may be 6..
4:40 PM
Mark M.
but for something that short, there will not be any actual recycling going on, so I do not know what RecyclerView gets you over a ConstraintLayout wrapped in a ScrollView
and with the ConstraintLayout/ScrollView approach, you could have all N RadioButtons be in a RadioGroup
Anshul V.
Is it possible I can implement this without the inner recyclerview? How would I go about setting the same answerViewHodler multiple times?
Mark M.
just toggle the visibility of unused RadioButtons to View.GONE
there would not be an answerViewHolder, as there would be no ViewHolder -- that is a RecyclerView construct
you would have the outer horizontal RecyclerView, and its ViewHolder would populate the TextView(?) for the question and the RadioButtons for the answers
(where in your case that population would happen via data binding, presumably)
and instead of a layout for the question and a layout for an answer, you would have a single layout for the question and 6 answers, with binding expressions for the text, answer visibility, etc.
Shawn W.
has entered the room
Mark M.
Anshul: let me take a question from Shawn, and I will be back with you in a bit
Shawn: hi! how can I help you today?
4:45 PM
Shawn W.
I haven't developed for Android since 2015. Which of your books would you suggest for a review and to get up to speed on new changes.
Mark M.
if you learn by reading, "Elements of Android Jetpack"
if you learn by doing, "Exploring Android"
right now, "Exploring Android" is a bit ahead of "Elements of Android Jetpack", though the latter will catch up in a few weeks
but either will give you an idea of how modern Android app development is being conducted
Shawn W.
Thank you very much. Your book helped me greatly when I started in 2010
Mark M.
great!
note that "Exploring Android" uses Kotlin, while "Elements of Android Jetpack" has examples in both Java and Kotlin
Shawn W.
Awesome. I wanted to start learning Koitlin
Mark M.
"Elements of Kotlin" covers the basics
and, since Google gave the "we will continue to support Java" kiss of death at last week's I|O, learning Kotlin is a really good idea :-)
(technically, they will support Java indefinitely, but it will soon be the second-class language for Android)
4:50 PM
Shawn W.
Thank you very much! I appreciate the advise. I have no more questions today.
Mark M.
OK -- feel free to join future chats as you start accumulating questions!
in the meantime...
Anshul: back to you! do you have another question?
Anshul V.
That's so interesting, Mark! I didn't know I could do it without inner recycler view. So I can have a List<QuestionAnswer> which comes from the server in the viewmodel, and another LiveData<List<QuestionAnswer>> which mirrors the adapter list in the activity, and we append question by question to the adapter list?
Mark M.
sure
just set up the layout for the question+answers to be what you want an individual "page" to be of your horizontal RecyclerView, and populate it in one shot
Anshul V.
Okay, thanks! Might I ask what should be the data structure for this purpose? the one where I can fill all the <QuestionAnswer> and can get the first question one by one to append to the adapter List<QuestionAnswer>?
Mark M.
um, well, your QuestionAnswer probably has the details of the question and a List of the details of the candidate answers
or, it could have individual properties for the candidate answers
since you have a fixed maximum number of them
and there aren't too many
Anshul V.
yes, the first one, details of the question, and list of details of the candidate answers
4:55 PM
Mark M.
it may not be much different than the data structure that you already have -- the difference is in what you do with the object in terms of setting up the UI
and I can't really give you specifics, as I do not know your app
Anshul V.
Well, the index of the horizontal recycler view would also come into play, since user can swipe back to see the previously answered question
Mark M.
yes, but that is outside of any individual QuestionAnswer
the horizontal RecyclerView works with a List<QuestionAnswer>
each page of that RecyclerView has widgets to display an individual QuestionAnswer
Anshul V.
Ah, right!
Mark M.
if it helps, ignore the horizontal aspect for a bit, and think of how you would show a vertically scrolling list of to-do items, or contacts, or whatever
in that case, the RecyclerView would have a List<Model> and each row would be rendering an individual Model
your situation is no different, except that you are scrolling horizontally
Anshul V.
Ha, change of perspective. Also, I think I know the answer to this, but to save the state of recyclerview (the checked radio buttons), if the user decides to swipe back, do I use savedInstanceState in the Activity to save recyclerview state?
Mark M.
primarily, it would be your top-level ViewModel, for handling configuration changes
it needs to know the users chosen answers, what the current question is, etc.
5:00 PM
Mark M.
putting that data in the saved instance state Bundle would be nice for process termination, though
fortunately, Google is adding support for tying the saved instance state Bundle into a ViewModel
Anshul V.
Hmm.. yeah, I heard about that but didn't explrore it. Thank you for all your help Mark! This helps!
Mark M.
happy to be useful!
and that's a wrap for today's chat
as usual, the transcript will be posted to https://commonsware.com/office-hours/ shortly
the next chat is tomorrow at 9am US Eastern
have a pleasant day!
Anshul V.
Have a good day!
Anshul V.
has left the room
Shawn W.
has left the room
Mark M.
turned off guest access

Thursday, May 9

 

Office Hours

People in this transcript

  • Anshul Vyas
  • Mark Murphy
  • Shawn W Vines