Office Hours — Today, July 5

Wednesday, July 3

Jul 5
3:50 PM
Mark M.
has entered the room
Mark M.
turned on guest access
4:00 PM
Shay
has entered the room
Shay
Hello
Good afternoon
Mark M.
hello, Shay!
how can I help you?
Shay
Hi Mark, hope you're doing well
Mark M.
trying to figure out why one of my servers is no longer accepting SSH connections :-(
otherwise, I'm fine -- and you?
quit
er, sorry, wrong window...
Shay
I am trying to achieve a RecyclerView that can have headers, and different layouts (with same Views), only mirrored for odd and even
4:05 PM
Mark M.
what do you mean by "mirrored"?
Shay
I'm fine, thanks
I have two layout containing views with the same IDs
Only on one of them there's an icon on the right, and then on the other the icon is on the left
basically for odd and even rows of the list
In addition, I need headers, which have a different layout alltogehter
I tried using a library called groupie, however it does not allow for layout changes based on position
I know I need to implement an adapter and ViewHolder. The question is, is there a better way to go about it
Mark M.
is there a better way to go about... what, exactly?
Shay
I need a RecyclerView that supports headers, and that I can change layouts based on position
Mark M.
and that will largely be the responsibility of your adapter
it will need to know the difference between headers, detail-odd, and detail-even positions
Shay
I got stuck a bit because of Kotlin
4:10 PM
Shay
in java I could make the ViewHolder take an object, then check what type it is
I cannot seem to do that in Kotlin
Mark M.
um, the same way that you do it in Java, though that overall approach isn't going to work, due to recycling
well, I shouldn't say "isn't going to work", but it will make things kinda messy
first: have you implemented getViewTypeCount() yet on your Adapter? if so, what value are you returning?
Shay
no, I cannot see this function
is it getItemViewType() in kotlin?
Mark M.
oh, yeah, whoops, I had the wrong method name there, sorry
are you implementing getItemViewType()?
4:15 PM
Shay
Not at the moment. I'll be honest and say I don't know this method
Mark M.
OK
Shay
I remember there used to be a function in Java getAdapaterPostion() or something like that
but cannot find it now
Mark M.
that's from ListAdapter with ListView (basically the same mistake that I was making earlier)
I recommend you read my chapter on "Advanced RecyclerView" in *The Busy Coder's Guide to Android Development*
in particular, I have a section on having a RecyclerView with headers + detail rows: https://wares.commonsware.com/app/internal/book...
it's in Java, but the concepts still hold
Shay
oh cool
Mark M.
to make multiple row types work with a RecyclerView, your adapter first needs to implement getItemViewType(), returning a unique integer for each distinct type of row, so RecyclerView recycles things properly
Shay
I actually tried to find something like that in the book, however I could only found the regular recycler view
Mark M.
*Elements of Android Jetpack* does not get into the advanced stuff
Shay
ah I see,
I guess it will take time and some edition to get there
Mark M.
well, not really, insofar as I don't intend *Elements of Android Jetpack* to cover the same scope as *The Busy Coder's Guide to Android Development* did
it's possible that I'll do an *Elements of Android RecyclerView* at some point that covers all the RecyclerView stuff in second-generation style
4:20 PM
Mark M.
but, in simple terms, I ain't rewritin' everything from a 4400-page book
but, that's why I added the full-text search to the sites, that span all books in the Warescription, to help you find the material that you need
Shay
yes, rewriting 4400+ pages sounds insane
Mark M.
anyway, getting back to your situation...
in your case, you have three types of rows: header, detail-odd, and detail-even, so getItemViewType() will need to return three distinct integers, based on which row type you want for this position
how you determine which row type you want for this position is part of your business logic, and it might get messy
but, once that's done, onCreateViewHolder() is passed the view type integer from getItemViewType(), so you can decide what to inflate and what sort of ViewHolder to return
and, onBindViewHolder() is passed the ViewHolder
in your case, I can see arguments for using either two or three distinct ViewHolder classes
headers definitely get their own
whether you use a single ViewHolder or two for the detail rows depends a bit on their contents -- if they truly are identical with just different layout positions, a single ViewHolder could work
Shay
yes, this is exactly the case
completely identical with different layouts positions
Mark M.
OK, so you can probably get by with a single ViewHolder class, where the Adapter inflates the proper layout based on the view type value
Shay
So I should implement a ViewHolder I take it (well, two)
Mark M.
yes
4:25 PM
Mark M.
one for the headers, and one for what I call the detail rows (you're welcome to use whatever term you want for those)
4:25 PM
Shay
so I basically need to implement a "parent" ViewHolder, then two that extends it I take it
unless the Adapter can take two different ViewHolders
Mark M.
you could have the adapter be an adapter of RecyclerView.ViewHolder, if you wanted
or have a common base class that the two ViewHolder implementations extend from
either way works
Shay
but isn't RecyclerView.ViewHolder an abstract class?
Mark M.
yes
however, RecyclerView.Adapter doesn't care
the reason you give RecyclerView.Adapter a data type for your ViewHolder is just to avoid casting in simpler scenarios
Shay
so I could get away with not creating a ViewHolder class, and only use getItemViewType and inflate in accordance
Mark M.
no
you asked: "so I basically need to implement a "parent" ViewHolder, then two that extends it I take it"
4:30 PM
Shay
Well, I'll explain myself better
You said I could also use RecyclerView.ViewHolder
Mark M.
and that's not necessarily required -- you could have two independent ViewHolder implementations, without a custom common base class
Shay
say I use RecyclerView.ViewHolder, can I just inflate the correct layout and be done?
Mark M.
no
let's back up a step
when I wrote "RecyclerView.Adapter doesn't care", I meant from a declaration standpoint
when you create your subclass, you need to tell it the type of ViewHolder that it manages
in a simple, all-rows-are-the-same scenario, that would be your custom ViewHolder subclass
you are not in that scenario
and so you have two choices for what to use in the <> for your Adapter declaration:
1. define a base class extending ViewHolder, use that in the <>, and have two subclasses of it, one for headers and one for detail rows
2. use ViewHolder itself in the <>, and have two subclasses of ViewHolder, one for headers and one for detail rows
you still need a ViewHolder class for your headers, and you still need a ViewHolder class for your detail rows
Shay
I see
Mark M.
the only variable is whether they directly extend ViewHolder or if they directly extend some other custom class of yours that extends ViewHolder
go with whichever you are more comfortable with
Shay
that does make much more sense. I didn't understand correctly before
Mark M.
yeah, I was a bit glib in my comment, sorry
Shay
It's fine
4:35 PM
Shay
It's close to midnight here, so I'm a bit slow
Also, it has been 2 years since I coded android, so I am very rusty
but it seems to me that extending RecyclerView.ViewHolder directly is less code and boilerplace
*boilerplate
Mark M.
agreed
Shay
and in any case the "header" and "detail" view have nothing in common
Mark M.
which would make a base class just a placeholder, which means it may not be worth it
Shay
so your second approach seems better
Exactly
Mark M.
yes
Shay
One thing though. When I use getItemViewType(), I should return the ID of the layout right? e.g. R.id as opposed to R.layout
Mark M.
it needs to be a unique integer
what the integer is does not really matter
and, unlike the old ListAdapter stuff, you don't have to start counting from 0
so, if you have distinct layout resources for each, and want to use R.layout values, that's fine
4:40 PM
Shay
So when I use getItemViewType(), the position parameter gives me the position in the current RecyclerView, as opposed to position in Adapter?
Mark M.
it should be an adapter position
Shay
Thats good. Only thing I'll need to do is remember the positions of the headers, because after each header odd and even starts anew
Mark M.
yeah, like I said, getItemViewType() might get messy
4:45 PM
Mark M.
OTOH, since the view type integer gets passed into onCreateViewHolder(), and the ViewHolder gets passed into onBindViewHolder(), you may be able to "contain the mess", as it were
Shay
Yes, it looks like it can get messy, true. But I think a simple boolean that knows if the count starts again can solve this
I'll see how it goes when I start coding
But in any case, thank you, you've helped me a lot and gave me the right direction, so I am grateful :)
Mark M.
you're welcome!
Shay
Well, I'll go to sleep a bit, I am a bit ahead of you (GMT+3 here). Going to write all your comments then code tomorrow when I'm fresh. Thanks again :)
Mark M.
um, sleep well! :-)
4:50 PM
Shay
Have great weekend, and late happy 4th of July :)
Shay
has left the room
4:55 PM
Mark M.
turned off guest access

Wednesday, July 3

 

Office Hours

People in this transcript

  • Mark Murphy
  • Shay