Office Hours — Today, March 3

Saturday, February 29

Mar 3
7:25 PM
Mark M.
has entered the room
Mark M.
turned on guest access
7:45 PM
Tad F.
has entered the room
7:50 PM
Tad F.
Hi Mark!
Mark M.
hello, Tad!
how are you today?
Tad F.
Plugging along....
Trying not to think about Coronavirus or the election drama :)
So here is a scenario I'm wrestling with...
I have an abstract class that I use in several places that has a lot of the plumbing in it to provide a visual "Master-Detail" capability.
The base layout this utilizes has an import statement for a commonly named layout, which varies based on whether the device is 600dp width or not.
Basically if it is 600dp or greater, then this layout shows both the "master" list on the left side, and a "detail pane" for the selected item in that list on the right side.
All good, and fairly standard I think.
The issue now, is that I'm implementing a new class that extends the base class.
I want everything that is in the base layout, but instead of this line that is in the base layout:
<include layout="@layout/item_list" />
I need to include a different layout *just for this one class*
7:55 PM
Mark M.
OK, first, what is the nature of the class? Is this an activity? A fragment? A view? Something else?
Tad F.
Base class is ListActivity
Classes that extend this do something different with their "list".
i.e. list of contacts, list of playlists, etc.
ContactListActivity, PlaylistListActivity, etc.
Mark M.
so, your abstract class extends ListActivity, and you have a subclass that extends the base class
Tad F.
Abstract class *is* ListActivity
The other classes extend that
ListActivity provides basic list management, causes items selected to be in a different color, etc.
Mark M.
so, you have your own class named ListActivity?
(and you're not referring to the ListActivity framework class?)
Tad F.
That's correct
Mark M.
ah, OK
Tad F.
It's a basic Master-Detail framework
It's actually modeled somewhat after what you get when you ask for a Master-Detail activity and Android generates it for you.
I just tweaked that (quite a bit)
Mark M.
yeah, I tried creating something like that 6-7 years ago and put it aside
Tad F.
It uses this layout
View paste (22 more lines)
<?xml version="1.0" encoding="utf-8"?>
<!-- Used by PlaylistListActivity -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_root_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.reddragon.intouch.ui.ListActivity">

    <!-- Style AppTheme.AppBarOverlay currently is defined as inheriting from ThemeOverlay.AppCompat.Dark.ActionBar
     and causes the a background using primaryColor background-->
    <com.google.android.material.appbar.AppBarLayout
...
(partial file obviously)
That last line is the problem child
8:00 PM
Mark M.
what's in it that needs to differ between your normal scenario and this one special scenario?
Tad F.
In the special scenario I don't want the layout to differ when the width is greater than 600dp
Actually - I do want it to differ - but only in one special case
But I'll set that aside for a sec
Mark M.
yeah, well, I think you're digging yourself a deeper hole
but, let's do set that aside
and let me try restating your situation:
you have layout/item_list.xml and layout-w600dp/item_list.xml
Tad F.
Right
Mark M.
and in this special scenario, you basically do not want layout-w600dp/item_list.xml to be considered
Tad F.
Mostly right, but let's assume that for now
Mark M.
that feels like Miracle Max and "mostly dead", but yeah, let's get to your next complexity later :-)
Tad F.
heh
Mark M.
you might somehow be able hack what you want with layout alias resources, but I am skeptical
oh, no, wait, that won't even help here
Tad F.
The deal is, this base layout is what I want for everything else. Seems silly to copy the whole thing over to a new file just to change that one line.
(which is what I'm doing at the moment)
8:05 PM
Mark M.
well, you could aim to move as much as possible out of the base layout into other <include>'d layouts, so item_list.xml is mostly a mashup, and your replacement for this scenario is a different mashup
Tad F.
Yeah - I was hoping there could be some sort of "classname qualifier" or "custom qualifier" I could invoke
Mark M.
not really
you could see if ViewStub could help: https://developer.android.com/reference/android...
I have never used it, but it offers a setter for the layout resource to use
that way, you could choose to replace the layout resource at runtime that gets inflated in place of the stub
at least, in theory
but, otherwise, I don't have a good solution for you
Tad F.
Hmmm...ok I'll look into that. I suppose I could make an abstract method in ListActivity getDesiredLayout() that each class has to return, and all but MediaListActivity would return item_list.
In case it is a layout that has qualifiers, would it then respect those qualifiers?
Mark M.
or, have a non-abstract getDesiredLayout() method, where ListActivity returns the default
Tad F.
Or do I now need to create a item_list_wide?
Yeah, right
I'm doing that now for some other methods
Mark M.
if by "it" in "would it then respect" is a ViewStub, it should respect those qualifiers
Tad F.
OK I'll look into that, thanks.
8:10 PM
Mark M.
basically, it's just hiding a bit of the LayoutInflater hassle for you, AFAICT
using LayoutInflater directly yourself would be another candidate solution, I suppose
Tad F.
Like, inflate it myself and add it to the parent view?
Mark M.
yeah, particularly if that FrameLayout wrapping your <include> has nothing else in it
give that FrameLayout an ID and inflater.inflate(getDesiredLayout(), yourFrameLayout)
Tad F.
Well it does, but it's one other container - a ConstraintLayout that has a bunch of stuff in it. But the good news, is that EITHER item_list or "empty_list" is made visible. Never both at the same time (one is a layout to use when there is nothing in the list, the other shows 1..N items in a list and various buttons, etc.)
Mark M.
yeah, that should not be a problem
the one headache with inflate() is that the inflated stuff gets added after all current children
Tad F.
So actually it would be to get a reference to the FrameLayout, and then dynamically add either the item_list or what have you as another child.
Mark M.
right
Tad F.
That's ok. It doesn't actually matter in this case which child is first, since only one of the two will be visible at a time.
Mark M.
agreed
basically, <include> itself is a fairly simple, inflexible thing
Tad F.
OK I think dynamically adding the child is the way to go.
8:15 PM
Tad F.
Now back to the little wrinkle :)
Mark M.
it shouldn't be a ton of code, in the end
(wrinkles aside)
Tad F.
So this MediaListActivity extends ListActivity like all the others.
What it does is shows the media list, in four different ways - but all use the same RecyclerView.
I adjust the layoutmanager, adapter and holder based on the "mode" the user is in.
It's like a Gallery where you can first scroll through CardView to select the year you want (with a few photos from that year in a StaggeredLayoutManager)
Or you can view by Month, or by Week
All those work the same, and I don't need the master-detail layout
Just the list
But if the user selects "all" mode, then you get the same list approach that all the other ListActivity derived classes use
So in that case, I'm back to needing to use item_list.xml, including the qualifier to have master-detail panes
on devices with widths >= 60dp
600dp
Mark M.
isn't that a matter of making the detail portion have visibility GONE when you are in modes other than "all"?
Tad F.
Well, there are a couple of other components in that layout (a FAB, a few other items) that allows the user to add/delete from the list. I suppose I could manage those as well to GONE when not in "all" mode.
8:20 PM
Mark M.
they aren't all in a common container representing the detail area?
(and, even if they aren't, but they are all in a ConstraintLayout, use Group)
Tad F.
No - there are effectively two FAB items here when in master-detail mode. On the left, there is one to add to the list. There can also be one on the right, because a single list "item" can actually have detail that needs to be added to it. A playlist for example has its own "one-to-many" relationship with the media items it "owns"
So in the base class, I tried to abstract that out
And let the detail pane handle showing/not showing that FAB.
I suppose if I just don't show the entire detail panel I can manage that...off the top of my head it still seems there was some other reason I was thinking I needed a separate layout, but I don't know remember why
I'll have to look at that.
Maybe you're right - I can just get away with making it GONE
Mark M.
that seems like it should be a reasonably straightforward solution, if perhaps a trifle clunky
Tad F.
Yeah - I'm already starting to see a bit too much of "if this condition then" creeping in...
Mark M.
you may need to consider adopting strategy patterns, rather than relying purely on ListActivity to handle all scenarios
8:25 PM
Mark M.
so, a subclass supplies one (or more) strategy objects that control how some of this stuff gets handled, and ListActivity largely delegates to the strategy objects
Tad F.
Yes, I had started looking into something like that - more composition patterns though.
Mark M.
same basic thing -- think of how RecyclerView handles things like adapters, item decorators, layout managers, etc.
Tad F.
Yes, exactly.
OK - thanks for your insight, as always!
Mark M.
happy to help!
Tad F.
And stay healthy there on the east coast!
Mark M.
thanks, you too!
8:30 PM
Mark M.
OK, that's a wrap for the chat!
the next one is Thursday at 8am US Eastern
have a pleasant evening!
Tad F.
has left the room
Mark M.
turned off guest access

Saturday, February 29

 

Office Hours

People in this transcript

  • Mark Murphy
  • Tad Frysinger