Aug 25 | 8:20 AM |
Mark M. | has entered the room |
Aug 25 | 8:25 AM |
Mark M. | turned on guest access |
Kai H. | has entered the room |
Mark M. |
hello, Kai!
|
Mark M. |
how can I help you today?
|
Kai H. |
Hello Mark
|
Kai H. |
My UX wants dividers/separators between groups of items in an overflow menu of an ActionBar.
|
Kai H. |
The items can be dynamic and are loaded depending on the items that are selected.
|
Kai H. |
The ActionBar is part of a contextual action mode.
|
Kai H. |
I am not sure how to achieve that.
|
Kai H. |
I have looked into grouping items in such menu, but haven't found anything about creating and deleting groups programmatically.
|
Aug 25 | 8:30 AM |
Mark M. |
I have not worked with contextual action bars in years
|
Mark M. |
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
|
Mark M. |
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
|
Mark M. |
and in that drop-down, you would populate it however you want
|
Mark M. |
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" :-)
|
Mark M. |
(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
|
Aug 25 | 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
|
Mark M. |
Marek: your turn! how can I help you today?
|
Marek D. |
we want to be reactive so we have a Flow
|
Marek D. |
let's say we want to track location updates
|
Marek D. |
so we have this fused client
|
Marek D. |
we register callback(s) and emit into flow when those come
|
Mark M. |
using callbackFlow()?
|
Marek D. |
yes
|
Marek D. |
but we want to pull to refresh as well
|
Marek D. |
I am not really sure how I should cause a location update in the flow
|
Marek D. |
I don't have any means to alter the flow
|
Marek D. |
other than starting it once again
|
Mark M. |
you wouldn't -- pull-to-refresh does not change the locatino
|
Mark M. |
er, location
|
Mark M. |
pull-to-refresh might reload some content from a Web service based on that location, or something like that
|
Aug 25 | 8:40 AM |
Marek D. |
yes we have something like this
|
Marek D. |
connected to the flow of location
|
Marek D. |
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
|
Mark M. |
and that seems reasonable
|
Aug 25 | 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
|
Marek D. |
but location takes time to get
|
Marek D. |
so if is not avaialble in one second I would send a request to web without location
|
Marek D. |
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
|
Mark M. |
(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!
|
Mark M. |
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
|
Mark M. |
combineLatest() is deprecated, but combine() might work -- I just have not used it for your use case
|
Mark M. |
let me take a question from Kumar, and I will be back with you shortly
|
Aug 25 | 8:50 AM |
Mark M. |
Kumar: your turn! how can I help you today>
|
Mark M. |
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...
|
Kumar V. |
Apparently it didn't work.
|
Mark M. |
sorry to hear that
|
Kumar V. |
View paste
|
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()
|
Mark M. |
(or however we get the content Uri associated with a StorageVolume -- I forget the details right now)
|
Mark M. |
in terms of the crashing, I wish Google did a better job in the CTS of testing this sort of thing :-(
|
Aug 25 | 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
|
Mark M. |
getContentUri() appears to be the long-term direction
|
Mark M. |
StorageManager can give you a list of StorageVolume objects
|
Mark M. |
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
|
Mark M. |
the hope is that, on your crashing devices, some StorageVolume has the stuff that you need
|
Kumar V. |
View paste
|
Mark M. |
OK, yeah, that's probably what MediaStore uses, not the StorageVolume stuff
|
Mark M. |
(I wish they were consistent...)
|
Aug 25 | 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
|
Mark M. |
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
|
Kumar V. |
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
|
Aug 25 | 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.
|
Kumar V. |
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
|
Mark M. |
in the end, other than improving the CTS, there is nothing really that Google is likely to do about it
|
Aug 25 | 9:10 AM |
Marek D. | has left the room |
Kumar V. |
Ok.
|
Kumar V. |
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
|
Mark M. |
multidex was added to Android 5.0, but they have a quasi-backport for older devices
|
Kumar V. |
Ok get it.
|
Kumar V. |
One general question about Kotlin, What's your understanding on kotlin removing checked exceptions
|
Kumar V. |
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
|
Mark M. |
and, since Kotlin supports environments beyond the JVM, it may be that not using checked exceptions helps in the porting process
|
Aug 25 | 9:15 AM |
Mark M. |
in terms of good and bad... I'm probably leaning on the side of good
|
Mark M. |
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
|
Mark M. |
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
|
Mark M. |
if, in the end, you have a huge batch of methods that just throw Exception... then checked exceptions did not buy you much
|
Mark M. |
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
|
Mark M. |
if *all* exceptions were checked, then the exception list in the method signature would have been complete
|
Mark M. |
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
|
Mark M. |
but Java IMHO is not that language
|
Aug 25 | 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)
|
Mark M. |
a consistent architecture and pattern for handling exceptions can address most of the exceptions
|
Mark M. |
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
|
Aug 25 | 9:25 AM |
Kumar V. |
That's it Mark.
|
Mark M. |
the chat is almost over, as well
|
Mark M. |
the transcript will be posted to https://commonsware.com/office-hours/ shortly
|
Mark M. |
the next chat is Thursday at 7:30pm US Eastern
|
Kumar V. |
Ok. Nice talking to you. Have a good day. :)
|
Aug 25 | 9:30 AM |
Mark M. |
you too!
|
Kumar V. | has left the room |
Mark M. | turned off guest access |