Office Hours — Today, April 20

Yesterday, April 19

Apr 20
7:20 PM
Mark M.
has entered the room
7:25 PM
Mark M.
turned on guest access
Mathias
has entered the room
Mark M.
hello, Mathias!
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
in case you fall asleep :-)
Mathias
Yeah, but i'm coding tomorrow!
so anyways...
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
its more about broadcastreceivers
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...)
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...
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
(BTW, hello Steve -- I will be with you shortly!)
Mathias
This is what i do in my BR:
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
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.
sure
Mark M.
Steve: your turn! do you have a question?
Steve S.
let me paste my question:
View paste
I am writing a new version of a kiosk app that provides an interface for a coffee brewer. The activity used to control brewing has (to simplify a bit) two states, resting and brewing, each associated with a different set of layouts. Communication between the app and the brewer is performed over Bluetooth using a service. The idea is that when the user presses the brew button, the app sends a Bluetooth message to the brewer to start brewing and the layouts are switched from resting to brewing. The layouts stay that way until brewing ends, at which point the brewer sends a message to the app and the layouts are switched back from brewing to resting.

If there were a way to guarantee that while the brewer is brewing, the activity won't be paused and the service won't be killed, this would be straightforward. (Towards this end, I am restricting lifecycle changes that can occur by setting keepScreenOn to true for the activity and by preventing navigation while brewing. Also, the Android device is fixed and cannot be rotated.)

Is there a way I can keep the activity from pausing while brewing? Is there a way I can keep the Bluetooth service from being killed while brewing?
Mark M.
um, well, you can look at the official kiosk mode stuff
showed up in Android 5.0 IIRC
this is the whole "pinned activity" thing
7:35 PM
Mark M.
I haven't looked at it
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
for example, if the user has access to the HOME button, you're screwed in lots of ways
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
your activity would not be stopped in that case, but it would be paused
in terms of the Bluetooth stuff, use a Service
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
using Android for this sort of use case implies certain amounts of flexibility
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
or, more accurately, develop as though a Murphy might use the device, and things go wrong
lots of things can go wrong
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
chike: your turn! do you have a question?
chike m.
let me paste it
View paste
I want to actually detect if there is internet connection. Especially on Wifi, if the android device is connected to the Wifi but actually there is no internect connection, this returns true
ConnectivityManager cm =
        (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
                      activeNetwork.isConnectedOrConnecting();
Mark M.
there is no such thing as "detect if there is an Internet connection"
there is only "detect if I can talk to a certain server"
chike m.
ok
so what approach would you suggest?
Mark M.
make a benign request to the server you are really trying to work wit
er, work with
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
Thanks
Mark M.
your code snippet might then be useful for determining what sort of error message to display
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
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
7:45 PM
Mathias
right
Mark M.
second, as you hinted, your process might end before the REST call completes
that will depend on lots of factors
and so it's one of those statistical things
frequently, it might work
but, some percentage of the time, it will not
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
yeah?
Mark M.
for a small REST call, IntentService should still be fine
but if it might take over a minute... strongly consider using JobScheduler
at least on Android O
Mathias
ok, is there any drawback to using jobscheduler?
Mark M.
it only exists on Android 5.0+
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
4.1
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
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
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
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
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:
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
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
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
and assume that it may go *poof* from time to time
Steve S.
ok, that makes sense.
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
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
Java objects don't run on threads
Java methods run on threads
the main lifecycle methods of a service -- onCreate(), onStartCommand(), onBind(), onDestroy() -- are called on the main application thread
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?
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?
*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
8:30 PM
Mark M.
turned off guest access

Yesterday, April 19

 

Office Hours

People in this transcript

  • chike mgbemena
  • Mark Murphy
  • Mathias
  • Steve S