Office Hours — Today, January 8

Saturday, January 4

Jan 8
7:20 PM
Mark M.
has entered the room
7:25 PM
Mark M.
turned on guest access
7:55 PM
Tad F.
has entered the room
Mark M.
hello, Tad!
how can I help you today?
Tad F.
Hi Mark!
I've got a nagging issue with a RecyclerView - I am attempting to dynamically bind it and show/hide widgets in the item layout based on data in the source.
What I'm seeing is that the holder being reused seemingly confuses the UI
Mark M.
"confuses the UI"?
Tad F.
I've set hasStableIDs, and also overridden getItemId() and getItemViewType()
per SO posts
but I'm still seeing it
Mark M.
what exactly is "it"?
Tad F.
Yeah - so what I mean is - some elements of the RecyclerView should have an icon that means the data in that item has a certain value, others dont have that value so the icon should not be shown.
What I'm seeing is that initially all looks good
Then as I scroll up and down, the icon appears in entries it shouldn't, and vice-versa
8:00 PM
Mark M.
are you always positively setting the visibility? IOW, are you guaranteed that in your bind function, you are always setting the visibility to some value, regardless of the data being bound?
Tad F.
Yes
Mark M.
or, are you saying "if the data is X, make the icon visible", and relying on some default for the data-is-not-X case?
Tad F.
Not relying on a default.
View paste
        if ( isMultiSelectMode ) {
            mVoiceOverImageView.setVisibility(View.GONE);
        } else {
            if ( ((Media)item).getAbsolutePathToAudio() != null && ((Media)item).getAbsolutePathToAudio().length() > 0) {
                mVoiceOverImageView.setVisibility(View.VISIBLE);
            } else {
                mVoiceOverImageView.setVisibility(View.INVISIBLE);
            }
        }
That's the last block of code in my onBind
Mark M.
is the icon the only thing that is not working? or are other elements in the views also messed up?
Tad F.
Just the icon
Mark M.
is getAbsolutePathToAudio() stable? IOW, will its data change for a given Media object?
Tad F.
Well, it could be null or an empty string, per the test.
Mark M.
but will the value change, for a specific instance of Media? IOW, is it mutable?
Tad F.
But for a given object in the recyclerview it is stable at the time the view is shown.
No - if the user clicks a button - new screen that allows them to record audio, and that path is stored. But on return I'm doing a notifyDataSetChange
8:05 PM
Tad F.
What I'm seeing is just scrolling the screen up and back, icon appears/disappears on a particular item.
Like moving it up just past the halfway point on the screen in one example triggered it.
Mark M.
wait... the icon changes while the view was still visible? not when the view scrolled off the screen and scrolled back?
Tad F.
Corect
correct
I'm assuming that holder is getting reused under the covers somehow...?
Mark M.
is anything other than your onBind() function affecting these widgets?
Tad F.
NO
No
Not at the time I am scrolling around anyway.
I do have a sort feature implemented.
But again - you change the sorted by, and I notifyDataSetChange
Mark M.
is the value of the item variable from your code snippet passed into onBind()? or are you holding onto it in a field?
Tad F.
The value is being held in a field.
Mark M.
that's not good for a viewholder
they're designed to be recycled
Tad F.
OK maybe that's it.
Base class onBind:
View paste (23 more lines)
        void bindItem(CardListable item) {
            mItem = item;
            // This uses a callout to a method that can be overridden by implementors, so that
            // the text that is shown can be altered - for example the Contact implementation
            // makes the description red text if it is null or empty (email address is required).
            mTitleTextView.setText(getFirstLineDescriptionText(mItem));
            mDescriptionTextView.setText(getSecondLineDescriptionText(mItem));
            updateThumbnailImageView(item, mThumbnailImageView);
            if ( isMultiSelectMode) {

                if (mCheckbox.getVisibility() == View.GONE) {
                    // Fade animation handled automatically via setting in the ConstraintLayout within
                    // item_list_content.xml
                    mCheckbox.setVisibility(View.VISIBLE);
                    mSettingsImageView.setVisibility(View.GONE);
...
Mark M.
I'd try to get rid of mItem (which I presume is your field)
8:10 PM
Tad F.
Hmmmm.....ok I'll look into that.
I assumed the lifetime of the holder until bindItem() was called again was ok.
Mark M.
let's just say it makes me nervous
Tad F.
That's a pretty big limitation now that I think about it....like the checkbox I'm using to indicate multi-select.
Mark M.
having mutable widgets in a RecyclerView itself is a pain
Tad F.
I set that in onbind based on an array where I'm keeping track of user selection.
Maybe what I need to do is actually just not keep mItem, but I can keep references to the other fields I bind?
That seems doable.
Mark M.
I'm not certain what "the other fields I bind" means in this context, so I can't comment on it
a viewholder can have references to the widgets in the view that it manages
Tad F.
That's what I mean
Mark M.
that's fine -- it's references to model objects that make me nervous
Tad F.
Here is an issue though, if I don't keep a reference to that item - I have a checkbox that should show checked if the user has selected the item or unchecked if not.
Right now, in the click listener for the checkbox I need to either set or unset the ID of the item associated with that holder at the time the user clicks the checkbox.
If I don't keep mItem in order to get the id at such time the user clicks the checkbox, how do I know what to set/unset?
Mark M.
if your list was stable, I'd say use the position index, but it sounds like your list is not stable
Tad F.
I'd have to set the click listener each time onBind is called?
Right now I do this in the constructor of the holder
8:15 PM
Mark M.
that would be another option, capturing the ID in the listener object
Tad F.
View paste (15 more lines)
       ItemHolder(View itemView) {
            super(itemView);
            cardView = (CardView) itemView;
            // Set listeners on the CardView
            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(this);
            itemView.setSelected(false);
            mTitleTextView = itemView.findViewById(R.id.item_list_content_title);
            mDescriptionTextView = itemView.findViewById(R.id.item_list_content_description);
            mThumbnailImageView = itemView.findViewById(R.id.item_list_content_image);
            mThumbnailImageView.setOnClickListener((View v)-> onThumbnailImageClicked(this));
            mSettingsImageView = itemView.findViewById(R.id.item_list_settings_image);
            mSettingsImageView.setOnClickListener((View v)-> onSettingsImageClicked(this));
            mCheckbox = itemView.findViewById(R.id.item_list_content_checkbox);
            mCheckbox.setVisibility(View.GONE);
...
Mark M.
if you want to try to keep mItem around, that's your call -- but then you are going to need to log the heck out of your binding logic and figure out who is calling it, when, and for what items
Tad F.
I get you.
I realize looking at this code that I'm passing 'mItem' fro the bindItem call out of my base class. Maybe I will try just passing the item that is the subject of the bindItem instead.
Mark M.
getting back to the root problem... in your original code snippet, you used all three visibility values
Tad F.
Not sure how I'm going to solve the issue with the checkbox listener though...
Yes
Mark M.
obviously, for cases where the icon is visible, you used VISIBLE
for the cases where the icon is missing when you expect it, can you tell by eyeball if it is INVISIBLE or GONE?
Tad F.
The reason is that in ACTION_MODE, I want voice-over icon (and there is a settings icon also that is always there), both GONE.
The checkbox should be the only one there, taking up real estate
Otherwise, I shift between visible/invisible to keep the dimensions stable between those two other icons (settings and voice-over)
That's all working ok.
May look a little strange, but it is correct.
Mark M.
that's fine -- I'm just trying to figure out if all three states are in flux, or just two
Tad F.
The checkbox is visible or GONE.
When the checkbox is visible, the other two icons are GON
When the checkbox is gone, the other two icons are either both visible, or the settings is visible and the voice-over is invisible
8:20 PM
Tad F.
That way, I don't have some entries with a much larger settings icon than others that are splitting real estate between settings icon and voice-over icon
Mark M.
except that the root problem is that this isn't working, and you are seeing or not seeing the icon at times when you expect the opposite
right?
Tad F.
Between checkbox and the other two icons, it is always working.
The problem is when checkbox is GONE, the other two icons aren't always showing correctly.
Gotta jump. Thanks for your input.
Happy New Year1
!
Tad F.
has left the room

Saturday, January 4

 

Office Hours

People in this transcript

  • Mark Murphy
  • Tad Frysinger