Jan 28 | 7:15 PM |
Mark M. | has entered the room |
Jan 28 | 7:25 PM |
Mark M. | turned on guest access |
Adam F. | has entered the room |
Mark M. |
hello, Adam!
|
Mark M. |
how can I help you today?
|
Caldwell S. | has entered the room |
Adam F. |
good evening
|
Caldwell S. |
Hola.
|
EGHDK | has entered the room |
Mark M. |
hello, Caldwell! Adam arrived just before you, so he gets the first shot, followed by you, then EGHDK (hi!)
|
Adam F. |
I have a situation i would like to describe and see if you have any suggestions
|
Mark M. |
Adam: do you have a question?
|
Caldwell S. |
heh heh Adam and I are from the same team. Love it.
|
Adam F. |
Yes
|
Caldwell S. |
Thanks for seeing us, Mark.
|
Caldwell S. |
Adam, do you want me to post the question?
|
Jan 28 | 7:30 PM |
Adam F. |
were using your piped content provider and we are having issues with some apps and mime types not loading correctly in third party apps ?
|
Mark M. |
OK
|
Adam F. |
Have you seen this behavior in the past?
|
Mark M. |
one known limitation is if the client needs to be able to rewind the stream, the stream from a ParcelFileDescriptor will not work
|
Mark M. |
(or, at least, from one created by createPipe())
|
Mark M. |
so, for example, you can't stream a video using the streaming provider approach
|
Adam F. |
I think thats the case as I know video content does.
|
Adam F. |
Would that entail writing the file out to disk?
|
Mark M. |
that's the only definitive case I know of that does not work
|
Mark M. |
would what entail writing what file out to what disk?
|
Caldwell S. |
Adam, may I post the full context of the question?
|
Adam F. |
Yes
|
Caldwell S. |
View paste
(18 more lines)
|
Caldwell S. |
View paste
(3 more lines)
|
Mark M. |
OK, give me a moment to read this...
|
Caldwell S. |
Roger that.
|
Mark M. |
other than the Gallery one, the rest would seem to fit the rewindable-stream issue
|
Mark M. |
not sure why Gallery would need that for an image, but I suppose I can't rule that out
|
Mark M. |
the only way I know of to get past the rewindable-stream issue is to use a ParcelFileDescriptor backed by an actual file
|
Jan 28 | 7:35 PM |
Mark M. |
which would imply writing the decrypted content out to disk, at least to internal storage
|
Caldwell S. |
We can remove the requirement of having to handle video files, for example, for v1.0.0.
|
Caldwell S. |
I think we're trying to determine if you think we're on the correct path by attempting to unencrypt the file on the fly by using a content provider.
|
Mark M. |
for arbitrary content, that's risky, as you're seeing
|
Adam F. |
My concern is that we cannot guaranty other interactions won't also cause issues.
|
Mark M. |
Adam: agreed
|
Mark M. |
in more controlled scenarios, it would be fine
|
Mark M. |
you can try the old "write a micro Web server and serve the content via HTTP" approach
|
Mark M. |
using some sort of dynamically-generated URL to prevent other apps from being able to hit your server
|
Adam F. |
Tried that and the browser takes control of every interaction
|
Mark M. |
(and only listening to localhost, of course)
|
Caldwell S. |
heh heh I think Adam attempted something like that.
|
Mark M. |
that too is not terribly shocking
|
Mark M. |
off the top of my head, I don't have a great answer
|
Mark M. |
though it's something I need to work on myself, for other reasons, in the not too distant future
|
Mark M. |
(by which I mean "2014" :-)
|
Caldwell S. |
We've certainly noticed an increase in requests from customers to further secure their content.
|
Mark M. |
completely understandable
|
Mark M. |
OTOH, bear in mind that once the data is in the hands of a third-party app, security goes out the window
|
Mark M. |
for example, the third-party app could off "Save As", its own "Share", etc.
|
Caldwell S. |
Agreed - and we've explained this scenario to the customer.
|
Mark M. |
/s/off/offer/
|
Jan 28 | 7:40 PM |
Caldwell S. |
Right. The third-party app could potentially write the stream to the disc.
|
Mark M. |
but right now, I don't have great answers for you
|
Caldwell S. |
No worries. We'll keep working at it, Mark. We may need to explain to them that when the user attempts to open a file, it may fail for certain apps; this is something that we can attempt to improve in the future.
|
Caldwell S. |
Security is very important to them. So, unless they want to change their point of view on this requirement, I don't know how we can make what we have any better at this time.
|
Adam F. |
Thanks for hearing us out
|
Mark M. |
conversely, keep tabs on my book, blog, and the StreamProvider project, as that's all where I'll be working on this stuff
|
Caldwell S. |
OK. Thank you, Mark. Have a nice evening.
|
Adam F. |
No worries we are.
|
Mark M. |
EGHDK: your turn! do you have a question?
|
EGHDK |
Yeah. Two of them.
|
EGHDK |
First one is something that I wrote down, but I don't remember from where. Could've been from you on SO, or Raomain from a GOogle i/o video. The quote is "getView returns a new view. New view is very expensive, especially if it comes from an xml file, which inflates it, which involves reflection."
|
EGHDK |
My question is reflection, and what does it have to do with this?
|
Mark M. |
all the *Inflater classes (LayoutInflater, MenuInflater, etc.) use reflection as part of converting the XML into Java objects
|
Mark M. |
for example, suppose you have a layout XML file
|
Mark M. |
the root element is <RelativeLayout>
|
Mark M. |
LayoutInflater, when it encounters that element, will use methods like Class.forName() to go find android.widget.RelativeLayout, then use methods like newInstance() on the Class object to create an instance of RelativeLayout
|
Jan 28 | 7:45 PM |
Mark M. |
reflection isn't the cheapest thing out there
|
Mark M. |
now, one could argue that LayoutInflater should just have some massive lookup table and avoid the reflection
|
Mark M. |
but then it could not handle <com.commonsware.android.MyCustomView>
|
EGHDK |
Gotcha.
|
EGHDK |
So which part of it is reflection... when you said "will use methods like Class.forName() to go find android.widget.RelativeLayout"
|
Mark M. |
Class.forName(), and using Java classes like Class and Method, are all considered part of the reflection API
|
EGHDK |
There are java classes called Class? and Method?
|
Mark M. |
yes
|
EGHDK |
Interesting.
|
Mark M. |
Java gets meta :-)
|
EGHDK |
Okay cool. Thanks for clearing that up.
|
Mark M. |
Adam: do you have another question?
|
Adam F. |
no I'm out and thanks for the assistance
|
Mark M. |
you're very welcome
|
Mark M. |
Caldwell: do you have another question?
|
Adam F. | has left the room |
Jan 28 | 7:50 PM |
Mark M. |
OK, EGHDK: do you have another question?
|
EGHDK |
Okay, so my second question is that I'm trying to build a sample messaging application like snapchat, but just for text messages.
|
EGHDK |
I'm sure you know, but snap chat basically has timers that will make a message dissapear.
|
Mark M. |
theoretically
|
EGHDK |
yep =)
|
EGHDK |
My app is super simple, I open up my activity and it reads a database that I populate myself, the database has a table of messages with three columns.
|
EGHDK |
_id, text, and seconds_remaining
|
EGHDK |
I load up the messages into a listView, and I show the text and seconds remaining in simple_list_items_2
|
EGHDK |
so that's super easy and it works fine.
|
EGHDK |
but now, I want to make the text View that holds the seconds remaining to tick.
|
EGHDK |
so each text view would update and incrementally go down every second.
|
EGHDK |
What would be the best way to do this? Do I have to call getView every second?
|
Mark M. |
you open up your favorite (::cough::) Android development book and search for ReverseChronometer
|
Jan 28 | 7:55 PM |
EGHDK |
Forget about the database or anything, I just want the seconds to count down in front of the users eyes.
|
EGHDK |
Oh! I learned about chonometer when I made a stop watch app. hahaha
|
EGHDK |
Reversechronometer makes sense.
|
Mark M. |
in version 5.5 of the book, ReverseChronometer is explained on pages 1131-1136
|
Mark M. |
as an example of a custom View
|
EGHDK |
Thanks.
|
Mark M. |
(BTW, those were PDF page numbers)
|
EGHDK |
got it
|
Tom | has entered the room |
Mark M. |
hello, Tom!
|
Tom |
Hello
|
Mark M. |
Tom: the others have all had a shot at questions so -- do you have a question?
|
Tom |
I have a question - it is about whether sync adapters are the right solution for my situation.
|
Tom |
My app has a custom log framework. If it encounters an error or exception then it dumps log info into a file. The issue is how/when to send those files to my server.
|
Mark M. |
I have not messed with SyncAdapter
|
Mark M. |
last I knew, it was difficult to use it outside of the whole Authenticator framework
|
Tom |
Ok, that's useful input.
|
Mark M. |
which means if this is the *only* thing you need to sync, I'd skip SyncAdapter, as that would be a headache for you and the user
|
Mark M. |
if, OTOH, this is one piece of a larger sync puzzle, and the Authenticator framework would be useful, then SyncAdapter may be a fine choice
|
Tom |
I think that answers my question - I should not use sync adapters.
|
Jan 28 | 8:00 PM |
Mark M. |
one of my 2014 projects is to get into SyncAdapter and figure out the leanest possible implementation, in terms of code, permissions, and user headache
|
Tom |
But I am still not quite certain when to schedule (launch) the service that sends my log files to the server.
|
Tom |
I wish there were a way to tell Android to schedule something when it will cost the user the least (e.g. middle of the night, when plugged in).
|
Caldwell S. | has left the room |
Mark M. |
well, you know when the middle of the night is for most ordinary users
|
Mark M. |
so, you could use AlarmManager to do something at, say, 4am
|
Mark M. |
unless this is one hella big file, I wouldn't worry about the device being plugged in, though
|
Tom |
Yes, so my current plan is to use AlarmManager and a pendingintent to launch my 'sync' service in the middle of the night.
|
Tom |
It shouldn't be too big - its a log file. Hopefully this will happen extremely rarely - only if there is an error or exception in the app.
|
Mark M. |
yeah, worrying about the power is definitely overkill
|
Mark M. |
and you might not even want to wait for the middle-of-the-night bit, if this is only a handful of KB
|
Tom |
Ok - maybe I'm over-thinking this one.
|
Mark M. |
the user is unlikely to notice a small power/bandwidth hit, and it may be important for the user, and you, to get the crashes faster than that
|
Mark M. |
for example, I don't think that the major crash-reporting solutions do aggressive batching like this
|
Mark M. |
leastways, ACRA doesn't
|
Mark M. |
and I'm not aware of others that do
|
Mark M. |
EGHDK: do you have another question?
|
Jan 28 | 8:05 PM |
Tom |
Yeah, you're right. Ok, thanks for the help.
|
Mark M. |
OK, if either of you have a question, go ahead
|
EGHDK |
Yeah, this one is about me having an app that has lets say 20 "important messages". These messages are loaded up into the database at the start of the app the first time you launch it. Then the application see if todays date matches the date associated with the important message, and then it displays that message in the app. What would I do if I also wanted to send a notification to the user, so that they don't have to open up the app after the first time
|
EGHDK |
Don't know if that made sense.
|
Mark M. |
um, use AlarmManager to get control at midnight, I suppose
|
Mark M. |
and use WakefulIntentService or WakefulBroadcastReceiver to arrange for a service to do the "hey! do we have an important message!" work
|
EGHDK |
I rather do it at like... 8am... so AlarmManger would have to do?
|
Mark M. |
I don't know how else you plan to get control at 8am daily
|
EGHDK |
Hahaha.
|
Mark M. |
if you have a server, I suppose the server could send a GCM message at 8am daily
|
EGHDK |
Well, I don't want it to go off every day at 8am I mean.
|
Mark M. |
but that's like swatting a fly with a Buick
|
Jan 28 | 8:10 PM |
Mark M. |
OK, now I'm lost
|
EGHDK |
Okay, let me start over.
|
EGHDK |
So, I have an app where I have a db with a table _id, message, date.
|
EGHDK |
When I open the app, I do a query to see if date in table == todays date.
|
EGHDK |
If it does, then grab the message and display it in the textView
|
EGHDK |
Simple.
|
EGHDK |
So this app has a DB of 20 "events/messages" that I know a year in advance.
|
EGHDK |
What would be the best way to show them in the notification. I don't want to create a check EVERY day. I already KNOW the days. Can I set alarms for a month in advance? 4 months in advance?
|
Mark M. |
you can try
|
EGHDK |
But is that practical?
|
Mark M. |
I have heard complaints that long-interval alarms are unreliable
|
Mark M. |
and you would also need to remember to rebuild your alarms on a reboot
|
EGHDK |
alarms aren't persistent?
|
Mark M. |
nope, they are wiped out on a reboot
|
Mark M. |
(or a Force Stop from Settings)
|
EGHDK |
Did not know. Okay.
|
Mark M. |
if you use a non-_WAKEUP alarm, the incremental power usage for your app checking today's messages is not that bad
|
EGHDK |
I feel like checking every day for something I know will only be used 20/365 days is overkill.
|
Jan 28 | 8:15 PM |
Mark M. |
understood
|
Jan 28 | 8:15 PM |
Mark M. |
and you're welcome to try setting the alarms that far out, and see how it works
|
Mark M. |
unfortunately, it's the sort of thing that takes a really long time to test
|
EGHDK |
So you think non-_WAKEUP alarm is the way to go?
|
EGHDK |
(Don't know what that is, but I'll look it up)
|
Mark M. |
personally, I'd probably go that route
|
Mark M. |
that's all covered in the rather long chapter on AlarmManager in the book
|
EGHDK |
Haha. Okay, I will take a look at that.
|
EGHDK |
I guess I have one more question/statement. Feel free to talk to Tom first.
|
Mark M. |
Tom: do you have another question?
|
Jan 28 | 8:20 PM |
Mark M. |
EGHDK: go ahead
|
EGHDK |
I'm kind of freaking out about the "Application" class. I feel like no one ever talks about it or uses it. I didn't even know about it, or its methods. onCreate() onTrimMemory(). I'm wondering why is that? Is application not used in most apps? If not... then when would you actually use it?
|
Tom | has left the room |
Mark M. | |
Mark M. |
that's the single best writeup of when to use what Context that I know of
|
Mark M. |
just tweeted about it again a few days ago
|
EGHDK |
Good article. I've "read" it many times.
|
EGHDK |
But is that "Context"?
|
EGHDK |
Is application just context?
|
Mark M. |
Application extends Context, just like Activity and Service do
|
Mark M. |
there are a few places where using Application as your Context is useful (e.g., something that will reside in a static data member, to prevent leaks)
|
Mark M. |
some people create custom subclasses of Application for the purposes of singleton-type stuff, but I haven't found much value in that
|
EGHDK |
Like a DB
|
Mark M. |
yes, a singleton SQLiteOpenHelper should use Application for its Context
|
Mark M. |
onTrimMemory() needs more love, though
|
Mark M. |
and I gotta cover it more in the book someday
|
Mark M. |
partly, that's because I totally misunderstood something about Dalvik
|
EGHDK |
Gotcha. Yeah, idk. I never knew Application existed really.
|
Mark M. | |
Mark M. |
once Andy Fadden clued me in on how Dalvik does release system RAM, onTrimMemory() made more sense
|
EGHDK |
Gothca.
|
Mark M. |
Application is "the red-headed step-child" of the Context realm
|
Jan 28 | 8:25 PM |
EGHDK |
Alright, well I have one more question. But times just about out, so I guess I shall save it for later.
|
EGHDK |
Activities don't extend from APplication in any way right?
|
Mark M. |
no, they do not
|
EGHDK |
Gotcha.
|
EGHDK |
Next time, get ready to answer what the hell a Bundle is for me.
|
Mark M. |
a Bundle is effectively a multiple-type-aware HashMap, that is Parcelable, so it can cross process boundaries
|
EGHDK |
...
|
EGHDK |
I just don't get the whole savedInstanceState thing.
|
Mark M. |
ah, that's a separate issue
|
EGHDK |
And I actually never saw it. I just thought it had to be there.
|
Mark M. |
did you read the resources and configuration change chapter?
|
EGHDK |
but I was usuing a library of yours, and you switched bundle for icicle or something, and I just noticed it.
|
Mark M. |
"Resource Sets and Configurations"
|
Mark M. |
pages 357-383 (PDF)
|
EGHDK |
Okay, I will read that next.
|
Mark M. |
onSaveInstanceState() is a method
|
Mark M. |
it takes a Bundle as a parameter
|
Mark M. |
you can call that parameter whatever you want
|
Mark M. |
the original 2007 conventional name was "icicle"
|
Mark M. |
because onSaveInstanceState(), at that time, was named onFreeze()
|
EGHDK |
I know. I just never "noticed" that it was even there hahah. I saw icicle and was confused... like "what is this?"
|
Mark M. |
by the time Android 1.0 rolled around, they renamed onFreeze() to onSaveInstanceState()
|
EGHDK |
oh!
|
Mark M. |
old-timers like me sometimes still call it the icicle
|
EGHDK |
That little analogy actually is helpful.
|
Mark M. |
you can call it "state", or "george", or whatever, since it is your method implementation
|
EGHDK |
yeah
|
Jan 28 | 8:30 PM |
EGHDK |
Gotcha. Okay, I will read about it. Thanks.
|
Mark M. |
and that's a wrap for today's chat
|
Mark M. |
next one is Thursday, 10am US Eastern Time
|
Mark M. |
I'll post this transcript to http://commonsware.com/office-hours/ shortly
|
Mark M. |
have a pleasant day!
|
EGHDK |
you too thanks
|
EGHDK | has left the room |
Mark M. | turned off guest access |