Office Hours — Today, August 25

Saturday, August 22

Aug 25
8:20 AM
Mark M.
has entered the room
8:25 AM
Mark M.
turned on guest access
Kai H.
has entered the room
Mark M.
hello, Kai!
how can I help you today?
Kai H.
Hello Mark
My UX wants dividers/separators between groups of items in an overflow menu of an ActionBar.
The items can be dynamic and are loaded depending on the items that are selected.
The ActionBar is part of a contextual action mode.
I am not sure how to achieve that.
I have looked into grouping items in such menu, but haven't found anything about creating and deleting groups programmatically.
8:30 AM
Mark M.
I have not worked with contextual action bars in years
I do not know if the built-in overflow menu has any notion of dividers
Kai H.
Well, shit :D
Mark M.
so, my gut instinct is that, if this can be pulled off, it will be through a custom ActionProvider
basically, you would not use the real overflow menu, but use your own ActionProvider to render the "..." and the drop-down, akin to how ShareActionProvider works
and in that drop-down, you would populate it however you want
the drop-down itself probably would wind up being a ListPopupWindow or PopupWindow
Marek D.
has entered the room
Kai H.
Sounds like a lot of hassle for a relatively small change.
Mark M.
agreed, but your designer is "coloring outside the lines" :-)
(Marek: hi! I will be with you shortly!)
Kai H.
You mean he wants something that is very uncommon?
Marek D.
hi!
Kai H.
Hello
Mark M.
I mean he wants something that is not part of stock Android UI, and in an area that has limited flexibility
8:35 AM
Kai H.
Thank you. I was thinking as much but wasn't sure. I guess I'll push back on that request then :)
Mark M.
let me take a question from Marek, and I will be back with you in a bit
Marek: your turn! how can I help you today?
Marek D.
we want to be reactive so we have a Flow
let's say we want to track location updates
so we have this fused client
we register callback(s) and emit into flow when those come
Mark M.
using callbackFlow()?
Marek D.
yes
but we want to pull to refresh as well
I am not really sure how I should cause a location update in the flow
I don't have any means to alter the flow
other than starting it once again
Mark M.
you wouldn't -- pull-to-refresh does not change the locatino
er, location
pull-to-refresh might reload some content from a Web service based on that location, or something like that
8:40 AM
Marek D.
yes we have something like this
connected to the flow of location
but this flow does not emit anything new
Mark M.
my guess is that you will need the logic to be in a separate function that can be both connected to the Flow<Location> and be invoked directly (using the last-seen Location)
Marek D.
(but that means the content of the ui does not change)
Mark M.
you would invoke that function directly for the pull-to-refresh scenario
Marek D.
ok i see
Mark M.
a side-effect of your Flow's collector would save the last-seen Location for use by the pull-to-refresh operation
Marek D.
so I would need to save that location in Viewmodel
Mark M.
if that is where the collector is, then yes
and that seems reasonable
8:45 AM
Mark M.
another, more complex, possibility would be to try something like combine() on the Flow
Marek D.
yes I though about combineLatest
but location takes time to get
so if is not avaialble in one second I would send a request to web without location
basically that gives me back the data (some landmarks) without a distance to it
Kumar V.
has entered the room
Kumar V.
Hello All.
Mark M.
I have not done much with combine() and I do not know how easy it would be to integrate here
(Kumar: hi! I will be with you shortly!)
Kai H.
I gtg, have a good day everyone :)
Marek D.
ok thanks1
Kumar V.
Sure
Mark M.
Kai: see you later!
Marek: Flow does not quite have the operator roster that, say, RxJava's Observable does, but I often forget about what operators it *does* have
combineLatest() is deprecated, but combine() might work -- I just have not used it for your use case
let me take a question from Kumar, and I will be back with you shortly
8:50 AM
Mark M.
Kumar: your turn! how can I help you today>
er, today?
Kumar V.
Hi Mark, it is the follow up question that I has asked couple of weeks back. https://stackoverflow.com/questions/63111091/ja...
Apparently it didn't work.
Mark M.
sorry to hear that
Kumar V.
View paste
There are two things with SO answer. 
MediaStore.Audio.Media.getContentUri( MediaStore.VOLUME_EXTERNAL_PRIMARY) --> returns the audios that are in internal storage and not the one in SDcard. 

And in few cases it still crashes.
Mark M.
in terms of the "not the one in SDcard", you would need to make multiple queries, using multiple Uri values that you get from getContentUri()
(or however we get the content Uri associated with a StorageVolume -- I forget the details right now)
in terms of the crashing, I wish Google did a better job in the CTS of testing this sort of thing :-(
8:55 AM
Marek D.
I have to go, byb bye
Kumar V.
Ya. This is the standard of querying media store for audio files. MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
Mark M.
Marek: good luck with the Flow!
Kumar V.
It works in all the cases and in the in house testing , but in production for few users it is crashing
Mark M.
Kumar: that is the original approach, but that is at least semi-deprecated now
getContentUri() appears to be the long-term direction
StorageManager can give you a list of StorageVolume objects
and you should be able to use getContentUri() to get a Uri for content on a StorageVolume, though I am not certain what you call on StorageVolume to pass into getContentUri()
Kumar V.
Ok, so get list of storage volumes and for each of these items you query audio tracks
Mark M.
right
the hope is that, on your crashing devices, some StorageVolume has the stuff that you need
Kumar V.
View paste
Set<String> volumeNames = MediaStore.getExternalVolumeNames(context);
String firstVolumeName = volumeNames.iterator().next();
Mark M.
OK, yeah, that's probably what MediaStore uses, not the StorageVolume stuff
(I wish they were consistent...)
9:00 AM
Mark M.
so, iterate over getExternalVolumeNames(), call getContentUri() for each value, and query for that Uri
Kai H.
has left the room
Mark M.
and concatenate the results
and, as it turns out, getExternalVolumeNames() uses StorageManager "under the covers", so I feel better about my initial guess :-)
Kumar V.
Ok. This is something critical for us, and we do some research before confirming the working, as with these api's it works in few and doesn't in few. We have 4.5M active users, and crash is happening for around 100 users, so not sure if we can ignore this
May be the crash would increase as and when more devices starts supporting Android 10.
Mark M.
yes, the slow march of Android versions occasionally has fringe benefits
9:05 AM
Mark M.
personally, I do not work with on-device media very much, and so I have not had to deal with this
Kumar V.
And nowhere in android documentation it is listed about this.
Mark M.
you sound surprised :-)
Kumar V.
Ha ha, no, I very well know this now.
I tried to raise an issue with Google but got rejected since I couldn't reproduce the issue. How do I handle this situation and prove to google that it is an issue.
Mark M.
do you have a specific device model in your lab that reproduces the crash? or are you working solely off of crash logs?
Kumar V.
Working based on the crash logs.
Mark M.
I would try to obtain a device that exhibits the problem, then use that and a project that reproduces the error
in the end, other than improving the CTS, there is nothing really that Google is likely to do about it
9:10 AM
Marek D.
has left the room
Kumar V.
Ok.
I have an another question. - What is the difference between extending Application and MultiDexApplication ?
Mark M.
the latter, IIRC, is for supporting multidex on Android 4.4 and older devices
multidex was added to Android 5.0, but they have a quasi-backport for older devices
Kumar V.
Ok get it.
One general question about Kotlin, What's your understanding on kotlin removing checked exceptions
Is it good
Mark M.
checked exceptions have long been controversial in Java, so I am not surprised that Kotlin elected not to use them
and, since Kotlin supports environments beyond the JVM, it may be that not using checked exceptions helps in the porting process
9:15 AM
Mark M.
in terms of good and bad... I'm probably leaning on the side of good
in complex systems, rarely is the call site the spot where you want to deal with the exception -- it's somewhere several calls up the call stack
so either you wind up with declaring the checked exceptions on all those methods, or you wind up throwing Exception or some other common supertype and losing the type details
if, in the end, you have a huge batch of methods that just throw Exception... then checked exceptions did not buy you much
and, since a lot of exceptions *aren't* checked exceptions, you still had to wrap calls in exception handlers to deal with RuntimeExceptions
Kumar V.
Ok, but let's say as api consumer if I don't get to know what exceptions I might be facing it could be bad at a later stage rigth
Mark M.
yes, but given RuntimeException, you were already in that position in Java
if *all* exceptions were checked, then the exception list in the method signature would have been complete
and so I cannot rule out the possibility that somebody could create (or has created) a programming language that has checked exceptions, but in ways that are not aggravating for developers
but Java IMHO is not that language
9:20 AM
Kumar V.
Yes. So as a developer we have to make a habit to know what the api does and what exception it might throw and decide to handle/ have a fallback. Provided the api is well documented.
Mark M.
or, just have common patterns for where you want to handle exceptions (e.g., when calling a repository from a viewmodel, assume that you might get an exception and route that to an appropriate viewstate)
a consistent architecture and pattern for handling exceptions can address most of the exceptions
it is then "death by 1000 paper cuts" for handling all the rest, for places that cannot abide by your architecture for one reason or another
Kumar V.
Ok, so should we be handling with generic "Exception" (or) with a specific exception that we anticipate from the method call
Mark M.
if there is something specific that you need to do for a specific exception, then handle it specifically :-)
Kumar V.
Ok
Mark M.
but if, say, an IOException is not special compared to any other type of Exception, there is no reason to catch IOException
9:25 AM
Kumar V.
That's it Mark.
Mark M.
the chat is almost over, as well
the transcript will be posted to https://commonsware.com/office-hours/ shortly
the next chat is Thursday at 7:30pm US Eastern
Kumar V.
Ok. Nice talking to you. Have a good day. :)
9:30 AM
Mark M.
you too!
Kumar V.
has left the room
Mark M.
turned off guest access

Saturday, August 22

 

Office Hours

People in this transcript

  • Kai Hatje
  • Kumar Velu
  • Marek Defecinski
  • Mark Murphy