Office Hours — Today, February 13

Tuesday, February 11

Mark M.
has entered the room
Feb 13
7:25 PM
Mark M.
turned on guest access
7:30 PM
Tad F.
has entered the room
Tad F.
Hi Mark!
Mark M.
hello, Tad!
how can I help you today?
Tad F.
We chatted a few months back about my decision for my app on whether to use ACTION_GET_CONTENT or ACTION_OPEN_DOCUMENT for the intent to allow users to select media for their playlists. I understand the ramification of each, and as a reminder my users need persistent URI because a) they want to define a playlist of media from locations not on their mobile device(i.e. Dropbox) that can be played now or later and b) they would rather not make copies of media that they already have stored in the cloud.
Mark M.
I vaguely remember this discussion!
Tad F.
View paste
So I implemented this with ACTION_OPEN_DOCUMENT and...ran smack into a 128 permission grants limit that you discussed with another user on SO some time ago: https://stackoverflow.com/questions/30802971/android-max-number-of-persistable-uri-permission-granted-to-an-app-is-limited-to/60174788#60174788
Ugh.
View paste
So it seems my choices are:
1. Not use persistable grants at all, which means either download copies or require that anyone creating a playlist know that the media may or may not be accessible (depending on where it is sourced) on a device reboot.
2. Manage the 128 in some sort of FIFO mechanism.
Any other options you can think of?
7:35 PM
Tad F.
Btw - the 128 limit is per document provider, and I had thought momentarily about doing some sort of "document provider per source", but in any event the limit will be reached...
Mark M.
there's a middle ground, of offering some sort of "pinning" feature, where you do the persistent permission thing only on pinned items
so you guarantee access to the pinned items, and it's YMMV for the unpinned ones
Tad F.
How would you see the UI working in that case? I have to prep the intent prior to launching the chooser, so it seems it's "all or nothing"?
Mark M.
the user would be limited to 128 pins
Tad F.
Present the list to the user and only do the take() method on those they want pinned
?
Mark M.
what list are you referring to?
Tad F.
The list of URIs returned back from the chooser.
Mark M.
oh, you're using EXTRA_ALLOW_MULTIPLE?
Tad F.
I have to prep the chooser with an intent that is ACTION_OPEN_DOCUMENT in order to be able to persist permissions as you know.
But that has to be done AHEAD of them choosing anything.
So say they choose 20 items.
I get a list of 20 URIs
I can take() the permission on 1 or all of them.
Are you suggesting I show them this list and ask which ones they want permanently?
Yes I am allowing multiple
Mark M.
well, I'm assuming that your playlist UI has some sort of a management set of UI actions for the items that are in the list: delete, reorder, etc.
7:40 PM
Mark M.
"pin" would be another such UI action
the catch is that you have to pin while you're still in the same process, which may be a problem
Tad F.
Exactly - its even worse
Mark M.
worse doesn't sound good
Tad F.
I have to know before I launch the chooser whether the intent should be 'prepped' to even allow pinning by using OPEN_DOCUMENT.
Then on return, I suppose I could have them indicate which ones are permanent or not
Mark M.
I don't understand
Tad F.
ok - maybe I am not thinking about this right...let's see step by step:
Mark M.
ACTION_OPEN_DOCUMENT does not care, up front, whether you will persist permissions or not
Tad F.
1. User wants to add item(s) to a playlist.
2. They tap the FAB which should launch a chooser.
3. I prep the OPEN_DOCUMENT intent in case I need one or more of their selections to be "pinned", because if they so indicate I need to do the takePersistableUriPermission() call on each one they want pinned.
4. They make their selection, and I get the list of URIs in ClipData
5. Now I have to present this list to them somehow BEFORE I finish processing to know which ones in the list I should exection takePersistableUriPermission() on?
Mark M.
OK, let's first talk about step 3
7:45 PM
Mark M.
AFAIK, your use of ACTION_OPEN_DOCUMENT has nothing directly to do with taking a persistable permission -- you want the user to pick some content, regardless
Tad F.
Well - yes and no.
Mark M.
whether you handle that content by taking a persistable permission, making a copy, or conceivably something else, is independent
Tad F.
If I didn't care about persisting, I probably would use GET_CONTENT because there are a hell of a lot more widgets that support that one. Including some they might already have on the device that are their "favorites" for managing their content.
But I punted on doing that because I couldn't persist the Uri.
But anyway -yes I get your point.
If I DO need to persist, I HAVE to use OPEN_DOCUMENt.
Mark M.
OK, so perhaps that's another way of going about the problem: instead of a post-hoc "pin", you offer "attach" and "import" options to the user, via floating action menu associated with your FAB
Tad F.
Said another way - OPEN_DOCUMENT allows me to choose whether or not to persist. GET_CONTENT doesn't
Mark M.
"attach" = ACTION_OPEN_DOCUMENT and a plan to persist the Uri permission
"import" = ACTION_GET_CONTENT and make a copy
Tad F.
Interesting idea.
Concerned that the user will get confused after a few playlists which items are which.
I suppose I could have a small icon or something to identify
Mark M.
for the "attach", if their number of selections blows past your 128 budget, you'd need to do something to tell them about that and have them prune things back, or convert some into "imported" items
7:50 PM
Tad F.
Yes - let me think about that. Maybe "link" is a better way to describe it than "attach"...
Mark M.
that term works too -- I'm certainly not sold on my choice of nouns :-)
but basically you expose the distinction, so the user can help you manage it
Tad F.
Right. yep. I like it.Speaking of "link", is there a way a user can spawn a chooser that would allow them to "select a link"?
i.e. there is some link on YouTube that is public, and they want to include that in their playlist.
How do I let them "choose a link"?
Mark M.
that's probably easier handled by you having an activity that supports ACTION_SEND, so they could share from the YouTube app
there isn't really a way for you to say "apps of the world (on this device), show me your links!"
Tad F.
They likely don't have the YouTube app on their device, or it could be links to a variety of other providers...
Mark M.
but then what would know about those providers, to be able to show links for them, if not your own app?
that's why a push option (ACTION_SEND) is more practical
Tad F.
OK I haven't looked into that, so I'm not very familiar with it - but I will.
Mark M.
for example, they could share a URL from their Web browser that is viewing the YouTube site that way
Tad F.
What does that imply?
How does that work?
Mark M.
you mean, how would you implement it?
Tad F.
So my app would respond to a "share" selection from the browser?
Mark M.
yes
you would have an activity with an <intent-filter> for an action of SEND and some MIME type, probably text/plain
(you would want to run some tests with major browsers to confirm what MIME type they use for their share options_)
Tad F.
OK - I actually already have that implemented, so that if they are using their camera to shoot an image or video they can share directly to my app and it handles it automatically by putting it into a playlist.
7:55 PM
Tad F.
Forgot this was ACTION_SEND... :)
Mark M.
for that, you're probably using image/jpeg or something, so you would just add support for another MIME type
if it is text/plain, examine it with a regex to see if it is a URL
if it is, handle it as you see fit
Tad F.
Hmmm....the links that YouTube (and others) come up with don't have any sort of common extension that would map to a known mime type do they
?
Mark M.
no, but you can use OkHttp or your favorite HTTP client to do a HEAD request and get the MIME type from the server
Tad F.
Is doing that explained in one of your books?
Mark M.
the HEAD request? I don't think I do that directly, though I show the use of OkHttp
Tad F.
I'm using OkHttp already for other things, so this would be a natural thing to do - but I need some pointers.
I suppose Ms. Google can help me out here...
Mark M.
so, if I'm reading that correctly, just chain head() onto the Request.Builder setup
Tad F.
OK - so what I need to do is:
Mark M.
then, your Response will have a header() function that you can call to retrieve the Content-type header
Tad F.
1. Extend my ACTION_SEND to include text/plain
2. For the non IMAGE/VIDEO share I get to process, determine if it is url
8:00 PM
Tad F.
3. If so, then use head() to determine if it is an image or video
4. If so, store it, if not ignore - perhaps with some sort of warning.
Right?
Mark M.
sounds about right
Tad F.
ok I'll look into that.
I also did file a bug report requesting that the 128 limit be revised. My suggestion was a property that can be set, a different exception to be thrown in case the limit was reached, and some sort of "recycle policy" framework that we can tap into.
I did get some feedback from Google, but I don't imagine this is terribly high on their priority list.
Mark M.
I'll be surprised if they allow you to set your own limit
however, it really needs to be raised past 128 -- that's just crazy small
Tad F.
They'be been pretty responsive on another bug I've found within Android Studio 3.6 RC 1-3 having to do with the CPU profiler, so I'll hope for the best on this one.
Mark M.
the tools team is better equipped for dealing with bugs than is the framework team
since the tools team gets to ship their own stuff, versus having to deal with firmware updates and the like
8:05 PM
Tad F.
Makes sense.
8:05 PM
Tad F.
I'll tell you - I've used a lot of IDE's over the years, and Android Studio in many respects is pretty freaking amazing. Those guys at Intellij also are wizards.
Mark M.
yeah, IDE tech has gotten a lot of love in the past several years
OTOH, not everyone can afford the RAM for these IDEs
so, you win some, you lose some
Tad F.
The improvements in the lint tools (both on demand and automatic) are freaky good.
Btw - do you recommend the auto-signing for the play store by Google, or do you think it is better to handle that phase yourself?
Mark M.
I hate auto-signing with the fiery passion of a thousand suns
my catchphrase for that is "you are what you sign"
if somebody else is signing the APK, they are the ones deciding what is in that APK
and I am anticipating some fairly ugly problems in the future based upon that
Tad F.
So I have an alpha version of my app up there for internal testing, and I did the auto-sign initially. I guess if I want to "start over", I need to delete the app entirely from the store and start from scratch?
Mark M.
I can't answer that, sorry -- I don't have enough experience with that particular flow
Tad F.
Will they let me use the same package name do you know?
ok
8:10 PM
Tad F.
Last question - are you keeping up with activity in the Flutter camp? Do you think it is here for the long haul?
I've got to do something for iOS, and am considering a "subset" of my app that would be on both platforms.
Mark M.
at this point, even if Google scaled back their involvement, I think there is enough of a community there that they would be able to push forward with it
Tad F.
Are you going to write a book on it?
Mark M.
if Fuchsia becomes something real and shipping, perhaps, as Flutter is the "native" UI for Fuchsia, if I understand correctly
Tad F.
My other consideration is that I'm fairly wedded to Realm as my persistence layer at this point, and they don't (as of yet) support Flutter.
Mark M.
does Realm support iOS? I haven't played with it much
Tad F.
Yes
It's really, really fast.
And sorta kinda like an object DB
Mark M.
well, the one project I helped on where they had used it on, we were ripping it out, so...
Tad F.
Interesting. Why?
And how long ago was that?
Mark M.
that would have been the latter half of 2018
and thread management was a big problem IIRC
the native library footprint was another
Tad F.
Were they just using the database? Or were they using Realm Cloud or Realm Server?
I'm just using the local database
Mark M.
just the local database
Tad F.
Hmmm...
Mark M.
I'm not saying Realm is evil, just that it wasn't popular on this project
Tad F.
I haven't seen threading issues - and it is really nice that my RecyclerViews automatically get updated when data is changed without me having to do anything.
8:15 PM
Tad F.
There are some pretty stiff rules about which threads can access which realm instances.
Mark M.
yeah, and I think that was causing problems with the RxJava layer we were using
Tad F.
You mention footprint - do you have a "rule of thumb" you like to use on app size?
Mark M.
or at least made it more difficult
not really, as it varies so much by app category
it's more of "is the space justified?"
Tad F.
Is this (fairly) new approach Google is pushing to modularize your app worth looking into? I'm currently still building everything into a single .apk file.
Mark M.
well, there are two somewhat independent things here:
1. Gradle modules
2. Dynamic feature modules
they are related, in that dynamic feature modules are implemented as Gradle modules
but you can still break up your app into multiple Gradle modules while still building a single APK
Tad F.
I'm actually not sure I get the use-case - is the idea that my app could be "MS Office" but all I want is to use PowerPoint, and so it dynamically gets downloaded and installed?
Mark M.
the primary benefit of multiple Gradle modules is build time, if you have some stuff with a fairly high build time -- isolate that in a separate module
Tad F.
OH - I thought this was something for end-user benefit...
Mark M.
you're describing dynamic feature modules
Tad F.
yes
8:20 PM
Mark M.
and while your example is larger than they're thinking of, you have the right basic idea
Tad F.
At least in my app, there are 4 main "features", but they don't make sense to use independently.
Mark M.
are there 1-2 that are core and the others are secondary, that some users might never use?
Tad F.
Manage Contacts, Manage Playlists, Manage Media Gallery, Share Content
Mark M.
oh, yeah, that's probably all core stuff
Tad F.
Not really.
Mark M.
another way to look at dynamic feature modules is "plugins, with less headache"
Tad F.
Gotcha
Mark M.
so, for example, if you offered image editing with a zillion filters, you might ship a few filters in the main APK and have other "packs" in dynamic feature modules
Tad F.
Yes, I see.
Mark M.
so that way the main APK isn't too huge, but the user can still fairly seamlessly get the other stuff
the downside is that AFAIK dynamic feature modules is a Play Store-only thing
so if your distribution plans go beyond that, you may encounter problems
Tad F.
Or if I end up writing DocumentProvider for different Internet resources (Flickr, Pintrest, Instagram, YouTube), I could ship one and have the others available.
Mark M.
yes, though those might not be big enough to warrant the effort
Tad F.
Right.
One of my design headaches I keep going back and forth on is whether to be the one that supplies the media chooser, or offer the ability for users to utilize their own which they may be familiar with.
Former lets me persist, the latter is more familiar to users (and I don't have to come up with a "My Gallery" module)
8:25 PM
Mark M.
well, as we discussed earlier, the answer might well be "both"
Tad F.
Yeah
Hey - thanks so much for your time, I'm going to drop. Really appreciate your insights.
Mark M.
happy to help!
Tad F.
When will this get posted to the transacripts?
Mark M.
in about five minutes :-)
Tad F.
cool.
Later!
8:30 PM
Mark M.
have a pleasant day!
Tad F.
has left the room
Mark M.
turned off guest access

Tuesday, February 11

 

Office Hours

People in this transcript

  • Mark Murphy
  • Tad Frysinger