Office Hours — Today, April 2

Tuesday, March 31

Apr 2
8:25 AM
Mark M.
has entered the room
Mark M.
turned on guest access
Kai H.
has entered the room
Mark M.
hello, Kai!
Kai H.
Hello
Mark M.
how can I help you today?
Kai H.
When something gets shared to my app, I use a Cursor, query() and eventually getString() to get the DISPLAY_NAME
for the shared content.
8:30 AM
Kai H.
I have found a case where DISPLAY_NAME is not set though.
8:30 AM
Mark M.
I was about to point out that possibility
not everything will support the OpenableColumns, of which DISPLAY_NAME is one
Kai H.
What would be the fallback in that case?
Mark M.
getLastPathSegment() on the Uri, perhaps
for a Uri of the form content://authority.goes.here/hey/this/seems/ni..., getLastPathSegment() returns nice.jpg
however, for a Uri of the form content://authority.goes.here/who/is/number/1, getLastPathSegment() returns 1
Kai H.
It's a content uri with a number and the end and no file type.
Mark M.
then you get to make something up, I guess
Kai H.
I have noticed that another app somehow gets the right file name. I did wonder how.
If there is some other query I can do or something.
Mark M.
can you paste the actual Uri here?
Kai H.
Unfortunately the "other app" is not open source
Sec
Working on it :D
8:35 AM
Kai H.
"content://media/external/file/764" in this case. I guess I can get the actual file name for that?
Mark M.
I would have expected DISPLAY_NAME to work for that
that should be from MediaStore
Kai H.
It's the "Huawei Files" file explorer that doesn't work for me.
Mark M.
is the other app that works a Huawei app?
Kai H.
No, it's "total commander"
Mark M.
you could try querying for the DATA column
that's deprecated as of Android 10 and was never reliable
but, it might return a filesystem path corresponding to this item
and while you may not have filesystem access to the content, the path will give you a filename
Kai H.
So the way to go is to try every possible way and experimentally determine which one gives the best file name? (setting a default if nothing "proper" is returned).
I was fearing as much, but still hoping for a "one fits all" solution
Mark M.
I'd phrase it more as trying a priority-ordered series of approaches
and taking the first one that returns something reasonable
but there is no "one fits all" solution
because this area is a mess and has been for *years*
Kai H.
I see
I do have another question
8:40 AM
Mark M.
go ahead!
Kai H.
I am making a form to forward something to several users in a specific order. The current idea is to have two tabs, one with general settings and one with the changeable list of users.
So you input the general information, then you go to the second tab and add as many users as you like, change the order of them until they are how you like and then you can send it all.
I do struggle on how to implement the "list of users" inside the ScrollView that usually makes up such forms for the app.
Mark M.
"list" usually implies a RecyclerView, not a ScrollView
Kai H.
And how to implement the ordering of users (drag and drop? arrows on the items? ...) and deletion and such.
Mark M.
you can use gestures (drag-and-drop reordering, swipe-to-delete) or visual controls (up/down arrows for reordering, X or trash can or something to delete)
if your user base will tend to be "digital natives", they probably know to try gestures like that, and you have less visual clutter, though the implementation is more complex
Kai H.
I was looking into ReyclerView with GestureHelper (or something), alternatively the approach with the arrows.
All of it in a NestableScrollView
Well, our user bsae is not digital native ;-)
Mark M.
if your user base might include a fair number of people who are not super-familiar with touchscreen interfaces, the visual controls are more discoverable
8:45 AM
Kai H.
And we use visual controls throughout the app, so I would stay with that for now.
Mark M.
that sounds reasonable, though the NestableScrollView might not be necessary -- that's only needed if you have other things on that tab besides the list
Kai H.
I will have a EditText for adding a user name
For example
And some additional information for the user.
Mark M.
another approach for that would be to have an "Add" item in the RecyclerView, which when clicked displayed a DialogFragment
if you did not want all of that to be in one big scrollable thing
Kai H.
And then have an edit button for the individual entries.
Mark M.
yes
if you were planning on using that form for edits... IMHO, that would be awkward
Kai H.
The last one is actually my current favourite for a prototype implementation.
All Content should always be displayed, which is why we use a ScrollView at the base. I found out that having a ListView inside of that is usually a bad idea.
8:50 AM
Mark M.
ListView is very old and does not know about nested scrolling
sudokai
has entered the room
Kai H.
That was a bit unclear: We have content on the form and when there is more content than display, the view should be scrollable, hence the Scrollview back then.
Hi Kai ;-)
sudokai
Hi! :)
Mark M.
Kai: I think our new user is claiming root privileges over you... so I'll be back with you shortly!
sudokai: hi! how can I help you today?
sudokai
Oh, no go ahead you guys first!
I'm still trying to find my code
Kai H.
Hehe. Been there...
Yes. RecyclerView does know about NestedView, but is harder to set up and all. Especially when TabHosts with ViewPager(2) comes into play...
Mark M.
OK, chime in when you are ready!
Kai: agreed, which is why I tend to prefer keeping the list purely a list and using something else for additional data collection (e.g., the DialogFragment)
but, that is really the decision of your graphic designers or whoever is making the UX choices
(IOW, not me)
Kai H.
I try to get some code out before they can make things too complicated :D
But I'll take that as a recommendation and implement it simple at first, with something else for data collection.
8:55 AM
Kai H.
But then I'll either need to not use a ScrollView at that place or use something other than a ListView for the list, right?
Mark M.
correct
both ScrollView and ListView are original API Level 1 widgets and are not well-suited for nested-scrolling scenarios
Kai H.
Ok. Thank you.
9:15 AM
sudokai
Mark, regarding the RecyclerView.ViewHolder RxJava subscription I mentioned last time, I'm really not sure how I can fix it.
I guess I need to rewrite the RecyclerView
Because I have 3 separate streams of data
The list itself and 2 more
Mark M.
these are Observable? Flowable? something else?
sudokai
Flowable I believe
I mean, there's no view model for the recyclerview
It's connected directly to a Realm list
9:20 AM
sudokai
Then there's some sort of event bus that emits updates
So the subscriptions are created in the viewholder
Mark M.
when you say "it's connected directly to a Realm list", what do you mean?
do you mean that you are observing a Flowable from Realm and are using that to update the RecyclerView?
sudokai
Well, Realm provides a class called RealmRecyclerViewAdapter
Mark M.
ah
sudokai
And my RecyclerView.Adapter is extending that
Mark M.
one option would be to not do that :-)
sudokai
Then in their base class, they hook up some realm change listeners, so it's sort of automagic
Mark M.
I forget Realm's RxJava API, as it's been a while since I used it
9:25 AM
sudokai
Because Realm emits the changes to the collection
Then RealmRecyclerViewAdapter updates the view
Mark M.
but if they have a way of giving you an Observable or Flowable for those changes, then you can use combineLatest() to assemble the RecyclerView contents from all of your observable sources (Realm, event bus, etc.)
(combineLatest() being a static method on Flowable and Observable)
sudokai
Because my data is not in a single Realm object, that's why there are 2 manually created subscriptions in the ViewHolder. Just giving you some context...
Okay, I'll check that
Mark M.
to avoid ViewHolders needing to subscribe to RxJava, the general approach I would take is:
1. Use a single observation system consistently (e.g., RxJava vs. RxJava + Realm-specific stuff)
2. Combine your multiple reactive sources when any of them emit (e.g., combineLatest())
3. Have that combined result be a List of pure data that represents what goes in the RecyclerView
4. Observe that combined reactive source in your activity/fragment
sudokai
Thanks a lot, I'll take a look, makes sense
Mark M.
5. Have your RecyclerView.Adapter subclass ListAdapter, with a suitable DiffUtil.ItemCallback
sudokai
Then I need a single source
Yeah
Mark M.
6. Call submitList() on the adapter when the combined reactive source emits a new list
the ListAdapter is set up to only modify the UI where needed, based on what is visible
sudokai
Oh, I remember this example in your book
Thanks
Mark M.
I definitely have some ListAdapter examples, though probably not one combining three reactive data sources
9:30 AM
Mark M.
and, that's all the time that I have for today, so that's a wrap for today's chat
the next chat is Saturday at 4pm US Eastern
have a pleasant day, and stay healthy!
Kai H.
Same :)
Kai H.
has left the room
sudokai
has left the room
Mark M.
turned off guest access

Tuesday, March 31

 

Office Hours

People in this transcript

  • Kai Hatje
  • Mark Murphy
  • sudokai