Apr 20 | 7:20 PM |
Mark M. | has entered the room |
Apr 20 | 7:25 PM |
Mark M. | turned on guest access |
Mathias | has entered the room |
Mark M. |
hello, Mathias!
|
Mark M. |
how can I help you today?
|
Mathias |
Hi Mark! man it's late here in stockholm... :)
|
Mark M. |
I have another early chat coming up on Monday
|
Mark M. |
in case you fall asleep :-)
|
Mathias |
Yeah, but i'm coding tomorrow!
|
Mathias |
so anyways...
|
Mathias |
I have some questions about broadcastreceiver and geofencing
|
Mark M. |
I have not played with geofencing much, but I can try to help
|
Mathias |
I have been using the geofencing for years, it works fine. i do a notification when users leave certain locations
|
Mathias |
its more about broadcastreceivers
|
Mathias |
I have quite a lot of stuff in my Application object, like a resthamdler, cachehandler etc. It's been great to have them always accessible (i know i could do singletons, but well...)
|
Mathias |
so i really would like to have access to that in my BR. However, the onReceive only has context and intent. When i re-visited my old code today, i noticed that i just cast my context to my Application class, and apparently its worked for years...
|
Apr 20 | 7:30 PM |
Mathias |
so first question: is this risky. Some threads on SO were wary. you know "theres no guarantee that it will be the application object always" etc
|
Mark M. |
I would consider that to be risky
|
Steve S. | has entered the room |
Mark M. |
and calling getApplicationContext() on the Context is dirt cheap
|
Mark M. |
(BTW, hello Steve -- I will be with you shortly!)
|
Mathias |
This is what i do in my BR:
|
Mathias |
ApplicationSession session = (ApplicationSession) context.getApplicationContext();
|
Steve S. |
thanks, Mark
|
Mathias |
(ApplicationSession) is my custom Application object
|
Mark M. |
that should be fine
|
chike m. | has entered the room |
Mathias |
ok, strange they don't have the API like that.
|
chike m. |
hello
|
Mark M. |
(BTW, hello, chike -- I will be with you after Mathias and Steve!)
|
chike m. |
ok
|
Mark M. |
Mathias: if you mean, "strange that they do not pass the Application into onReceive()", they probably wanted more flexibility
|
Mathias |
right
|
Mathias |
yes thats what i meant
|
Mark M. |
let me take questions from the others, and I will be back with you for follow-up in a little bit
|
Mathias |
second quick question: The reason for my looking at this is because want to make a server rest call in my onReceive. Is there anything in particular i need to think about? I saw something in your section about it that it might be shut down if it takes too long to complete.
|
Mathias |
sure
|
Mark M. |
Steve: your turn! do you have a question?
|
Steve S. |
let me paste my question:
|
Steve S. |
View paste
|
Mark M. |
um, well, you can look at the official kiosk mode stuff
|
Mark M. |
showed up in Android 5.0 IIRC
|
Mark M. |
this is the whole "pinned activity" thing
|
Apr 20 | 7:35 PM |
Mark M. |
I haven't looked at it
|
Mark M. |
but it was designed with this sort of single-use scenario in mind
|
Steve S. |
ok
|
Mark M. |
beyond that, this is really a matter of how you are controlling overall navigation
|
Mark M. |
for example, if the user has access to the HOME button, you're screwed in lots of ways
|
Mark M. |
so I'm assuming that you already have that taken care of
|
Steve S. |
right, the user has access to none of that
|
Mark M. |
another pause scenario would be if some system dialog were to appear
|
Mark M. |
your activity would not be stopped in that case, but it would be paused
|
Mark M. |
in terms of the Bluetooth stuff, use a Service
|
Mark M. |
particularly a bound service, given the Android O changes
|
Steve S. |
that's what I was going to do. but I haven't seen a way to guarantee that a service won't be killed (even if it's a foreground service)
|
Mark M. |
nothing in Android is guaranteed
|
Mark M. |
using Android for this sort of use case implies certain amounts of flexibility
|
Mark M. |
but you have orders of magnitude greater chance of keeping a foreground service alive than preventing an activity from being paused
|
Steve S. |
that was my concern. so it sounds like the only foolproof approach (unless the Android kiosk stuff would work) would be to allow for the possibility that the activity will be paused and the service will be killed?
|
Mark M. |
yes
|
Mark M. |
or, more accurately, develop as though a Murphy might use the device, and things go wrong
|
Mark M. |
lots of things can go wrong
|
Apr 20 | 7:40 PM |
Steve S. |
ok. I thought you might say that!
|
Mark M. |
let me take questions from the others, and I'll be back with you in a bit
|
Mark M. |
chike: your turn! do you have a question?
|
chike m. |
let me paste it
|
chike m. |
View paste
|
Mark M. |
there is no such thing as "detect if there is an Internet connection"
|
Mark M. |
there is only "detect if I can talk to a certain server"
|
chike m. |
ok
|
chike m. |
so what approach would you suggest?
|
Mark M. |
make a benign request to the server you are really trying to work wit
|
Mark M. |
er, work with
|
Mark M. |
so, for example, if you are trying to work with a Web server, do an HTTP HEAD request on /robots.txt or something
|
chike m. |
ok, I get it now
|
chike m. |
Thanks
|
Mark M. |
your code snippet might then be useful for determining what sort of error message to display
|
Mark M. |
let me take questions from the others, and I will return to you in a little bit
|
chike m. |
ok
|
Mark M. |
Mathias: back to you! yes, you really really really want to use an IntentService or JobService there
|
Mathias |
ok
|
Mathias |
so the reason it has worked is because i only threw up local notifications?
|
Mark M. |
first, onReceive() is called on the main application thread
|
Mathias |
and that was quick
|
Apr 20 | 7:45 PM |
Mathias |
right
|
Mark M. |
second, as you hinted, your process might end before the REST call completes
|
Mark M. |
that will depend on lots of factors
|
Mark M. |
and so it's one of those statistical things
|
Mark M. |
frequently, it might work
|
Mark M. |
but, some percentage of the time, it will not
|
Mark M. |
using an IntentService or JobService will improve your chances considerably
|
Mathias |
ok so intentservice it is!
|
Mark M. |
particularly if the work might take some time
|
Mathias |
it shouildn't, just a small rest call
|
Mark M. |
note that on Android O, IntentService is not going to be as popular
|
Mathias |
but still
|
Mathias |
yeah?
|
Mark M. |
for a small REST call, IntentService should still be fine
|
Mark M. |
but if it might take over a minute... strongly consider using JobScheduler
|
Mark M. |
at least on Android O
|
Mathias |
ok, is there any drawback to using jobscheduler?
|
Mark M. |
it only exists on Android 5.0+
|
Mark M. |
and it's a bit more cumbersome to set up
|
chike m. | has left the room |
Mark M. |
if your minSdkVersion is below 21, you'll probably wind up with an IntentService, at least for those older devices
|
Mathias |
oh, that's a no-starter, our min is 16
|
Mathias |
4.1
|
Mathias |
tons of companies with old, cheapo units you know
|
Mark M. |
yeah, so either use IntentService across the board and hope those REST calls are short, or use IntentService pre-O and JobScheduler on O+
|
Mathias |
there's no way it should take more than one minute....
|
Mark M. |
then IntentService should suffice
|
Apr 20 | 7:50 PM |
Mark M. |
and, actually, if you get nervous and don't mind the UI impact, making it a foreground service also clears up the O issues
|
Mathias |
i think i have a socket timeout of 30 secs in my spring restclient
|
Mark M. |
that requires a Notification, which not everybody is willing to accept
|
Mark M. |
OK
|
Mathias |
not following totally, this is for geofence alerts, it will mostly be in the background when app is not running
|
Mark M. |
OK
|
Mark M. |
so, to sum up: use getApplicationContext() and an IntentService
|
Mathias |
:) thanks mate!
|
Mark M. |
let me switch back to Steve, and if you're still awake, I'll return to you shortly
|
Mark M. |
Steve: back to you! do you have another question?
|
Mathias |
i think i'm done! good night!
|
Steve S. |
following up on our earlier discussion:
|
Steve S. |
I have looked a bit into the built-in kiosk support, but it looked quite complex, so I was looking for alternatives
|
Mathias | has left the room |
Steve S. |
If I didn't use that, could I get what I want by keeping track of the UI state in the app so it could be restored in onResume(), and resending messages to the app from the brewer if the service were killed?
|
Mark M. |
well, tracking state is part of how we normally implement activities
|
Steve S. |
ok
|
Mark M. |
ideally, your activity is relatively disposable
|
Apr 20 | 7:55 PM |
Steve S. |
what do you mean by "disposable"?
|
Mark M. |
now, in your case, you probably won't *need* to dispose of it much
|
Mark M. |
well, in an ordinary Android app, activities get destroyed all over the place: BACK button presses, configuration changes, background process termination, etc.
|
Steve S. |
oh sure
|
Mark M. |
your situation is not especially normal
|
Steve S. |
right
|
Mark M. |
but, rather than engineering around *relying* upon the activity being around all the time, build it normally
|
Mark M. |
and assume that it may go *poof* from time to time
|
Steve S. |
ok, that makes sense.
|
Steve S. |
this case is a bit more complicated, though, since the app must not only keep track of its own state, but look for changes in the brewer state that might have occurred while the activity was paused
|
Steve S. |
but it sounds like there's no easy way around dealing with that
|
Mark M. |
put the communication with the brewer in a foreground service
|
Steve S. |
ok. question on that: does a foreground service run in the UI thread?
|
Mark M. |
a service is a Java object
|
Mark M. |
Java objects don't run on threads
|
Mark M. |
Java methods run on threads
|
Mark M. |
the main lifecycle methods of a service -- onCreate(), onStartCommand(), onBind(), onDestroy() -- are called on the main application thread
|
Mark M. |
your own business logic runs on whatever threads suit your purpose, and usually *not* the main application thread
|
Steve S. |
so what thread is used for a method on a foreground service would be up to the method, and I could spawn a new thread to run it in?
|
Apr 20 | 8:00 PM |
Mark M. |
sure
|
Steve S. |
ok
|
Mark M. |
if you use the command pattern and startService(), your service gets control in onStartCommand(), and you can set up a thread pool or whatever
|
Steve S. |
ok. so using a foreground service would make it less like the service would be killed, but a foolproof approach would require accommodating the possibility that it could be killed?
|
Steve S. |
*likely
|
Mark M. |
I would expect a foreground service to last for days
|
Steve S. |
ok
|
Mark M. |
particularly if you take care to avoid memory leaks
|
Steve S. |
this has been very helpful, Mark. Thank you!
|
Mark M. |
you're welcome!
|
Steve S. |
I will chew on this. Have a good rest of the day!
|
Mark M. |
you too!
|
Steve S. | has left the room |
Apr 20 | 8:30 PM |
Mark M. | turned off guest access |