Feb 10 | 7:20 PM |
Mark M. | has entered the room |
Feb 10 | 7:25 PM |
Mark M. | turned on guest access |
Feb 10 | 7:30 PM |
Jan v. | has entered the room |
Jan v. |
Hi Mark :)
|
Feb 10 | 7:35 PM |
Mark M. |
hello
|
Mark M. |
sorry if there was a short delay there
|
Mark M. |
they disabled the beeps on this chat
|
Mark M. |
gonna drive me nuts 'til I write a replacement chat app
|
Mark M. |
anyway, how can I help you today?
|
Jan v. |
I'm going to paste in some framework and questions...
|
Jan v. |
View paste
(9 more lines)
|
Mark M. |
oboy
|
Jan v. |
Basically, I'm looking for some fundamental guidance on how to not mess it up totally.
|
Mark M. |
first, is this an app for public distribution (e.g., Play Store), or for a more constrained audience (e.g., employees of a firm)?
|
Jan v. |
No, very constrained, to say, a modern handset like a Nexus 5x
|
Mark M. |
ok
|
Mark M. |
with regards to 1+2, are you setting this up as some sort of kiosk app (i.e., your UI is guaranteed to always be in the foreground)?
|
Jan v. |
I see where you coming from because Android itself is evolving fast
|
Mark M. |
or is the user potentially switching between this app and other things (e.g., incoming calls)
|
Mark M. |
?
|
Feb 10 | 7:40 PM |
Jan v. |
It's being envisioned as a "normal" app, i.e. it has to function around other potential apps.
|
Mark M. |
Ok
|
Mark M. |
in that case, you definitely need to use a service
|
Jan v. |
Ok, check.
|
Mark M. |
while the Application instance is around while your process is around, your process just won't be around all that long while your app is in the background, if you don't have a service
|
Jan v. |
Will the service be essentially just to "keep the app open?"
|
Mark M. |
it will be telling Android "hey, I'm workin' here!"
|
Mark M. |
(delivered in a great Al Pacino impersonation)
|
Mark M. |
more specifically, you probably want to use a foreground service, where you call startForeground() and put a Notification up
|
Mark M. |
even then, your process will live for days, but probably not weeks
|
Jan v. |
Ok, understood
|
Mark M. |
#3, a ScheduledExecutorService seems like a reasonable choice, given your requirements
|
Mark M. |
#4, um, use ViewPager
|
Mark M. |
#5, use an in-process event bus (greenrobot's EventBus is my personal preference, though there's Square's Otto, plus LocalBroadcastManager)
|
Mark M. |
#6 I don't understand, sorry
|
Mark M. |
#7 hook the device up to a hydroelectric dam
|
Mark M. |
because battery life is going to suck by definition
|
Feb 10 | 7:45 PM |
Mark M. |
a primary feature of this app appears to be to drain the battery as fast as possible
|
Mark M. |
:-)
|
Mark M. |
as it stands, you need the CPU to be powered on 100% of the time (e.g., WakeLock)
|
Mark M. |
GPS every 10 seconds will keep the GPS radio powered on 100% of the time
|
Mark M. |
doing network I/O every 30 seconds will keep some radio (WiFi or cellular) in a mid-to-high power state close to 100% of the time
|
Mark M. |
maybe the screen turns off
|
Mark M. |
but otherwise, you're hitting on all the big sources of battery drain, and there's not a lot you can do about that, given the stipulations of your app
|
Jan v. |
Right.
|
Mark M. |
BTW, on Android 6.0, you're going to need to add this app to the battery optimization whitelist in Settings
|
Mark M. |
otherwise, Doze mode will shut you down, along with everything else, if the device is not moving
|
Jan v. |
The AlarmManager would have been nice, but minimum duty cycle is 60s.
|
Feb 10 | 7:50 PM |
Mark M. |
yup
|
Jan v. |
Ok I'm chewing on your responses a bit, questions coming up in a few :)
|
Mark M. |
no worries
|
Mark M. |
ordinarily, I time-slice between folks, but it's just you at the moment
|
Jan v. |
So, given a ScheduledExecutorService, would I create the two looping threads inside the service?
|
Mark M. |
I'm not sure what the two looping threads are
|
Mark M. |
you have two tasks scheduled in the ScheduledExecutorService
|
Mark M. |
the every-10-seconds one and the every-30-seconds one
|
Mark M. |
they each do their work
|
Mark M. |
they post messages on an event bus for consumption by the UI layer, if that UI layer is around
|
Feb 10 | 7:55 PM |
Jan v. |
is that the "greenrobot" thingy?
|
Mark M. |
your control screen tells the service when to start, stop, and change polling periods
|
Mark M. |
greenrobot's EventBus is one of three major event bus implementations for Android, yes
|
Mark M. |
the other two are Square's Otto and LocalBroadcastManager
|
Mark M. |
the latter is part of the Android Support libraries, but it's not nearly as nice as the other two
|
Mark M. |
I cover the event bus pattern in the chapter on threads
|
Jan v. |
does it use the standard intent messaging ?
|
Mark M. |
and I have a later chapter comparing and contrasting these three implementations
|
Mark M. |
LocalBroadcastManager uses Intents, but only to provide an API that feels like traditional system broadcasts
|
Jan v. |
ah ok
|
Mark M. |
the other two libraries do not use Intents, which gives them more flexibility
|
Mark M. |
none of the three can start a component (e.g., start an activity, start a service)
|
Mark M. |
they are for inter-component messaging within a running process
|
Mark M. |
and they provide a fairly nice pattern for decoupled communications, such as from a service back to the activities/fragments/whatever that make up the UI
|
Mark M. |
there are other approaches to solving that problem, but I usually steer people to an event bus
|
Jan v. |
So let's say the user activity has started the service which started the 10s and the 30s logging thread.
|
Feb 10 | 8:00 PM |
Jan v. |
If that service gets killed somehow, i would have to insert code that reads the run state from say, sharedPrefs, so when it gets restarted, it can take off where it was, right?
|
Mark M. |
first, it's not so much that the service alone gets "killed", as your process gets terminated
|
Mark M. |
that can happen naturally on Android, to free up system RAM for other processes, though the foreground service will minimize the occurrences
|
Mark M. |
but, if the user powers down the device, the battery runs out, the battery *falls* out, etc., you won't have a running process anymore
|
Mark M. |
any state that you care about needs to be persisted
|
Mark M. |
what's in RAM is purely a cache or transient stuff
|
Mark M. |
whether you use SharedPreferences or a SQLite database or some other sort of file is up to you
|
Jan v. |
Ok.
|
Jan v. |
What class would you choose for the two primary threads?
|
Mark M. |
I don't really understand
|
Jan v. |
or is that forced by the ExecutorService
|
Mark M. |
ScheduledExecutorService takes a Runnable or a Callable as the thing that is the embodiment of the periodic work
|
Jan v. |
ok
|
Feb 10 | 8:05 PM |
Mark M. |
usually, for this sort of thing, I'd use Runnable
|
Jan v. |
ok, check with what i thought
|
Jan v. |
when you run out of work in your runnable, you just return, right? The scheduler will take care of the next run, right?
|
Mark M. |
yup
|
Mark M. |
automagically :-)
|
Jan v. |
yiha!
|
Jan v. |
is the System Nano timer the best timing resource for accurate timing of the up and download tasks?
|
Mark M. |
um, probably
|
Mark M. |
haven't done much of that
|
Feb 10 | 8:10 PM |
Jan v. |
A viewpager, are you forced to use fragments or can you use viewgroups
|
Mark M. |
ViewPager uses a PagerAdapter
|
Mark M. |
PagerAdapter itself deals with views
|
Mark M. |
however, PagerAdapter is abstract
|
Mark M. |
the two concrete implementations are FragmentPagerAdapter and FragmentStatePagerAdapter
|
Mark M. |
as you might guess, those use fragments
|
Mark M. |
however, you can create your own PagerAdapter implementation that avoids the fragments
|
Mark M. |
I have at least one example of that in the book
|
Jan v. |
yay
|
Jan v. |
\0/
|
Jan v. |
if you have a file open that you're writing to, and you get destroyed, do you get some extra time to close your files or do you have to assume the absolute worst? If so, how do you avoid indeterminate file writes?
|
Mark M. |
that depends on how your process is being terminated
|
Feb 10 | 8:15 PM |
Mark M. |
normally, the out-of-memory killer will trigger onDestroy() on all running activities and services in your process
|
Mark M. |
however, that's not guaranteed (e.g., user force-stops you from Settings, battery runs out)
|
Jan v. |
is there a way in adb to simulate some of the rarer events?
|
Mark M. |
um, I assume that there's an adb command that's the equivalent of killing the process from the IDE
|
Mark M. |
yes, adb kill your.application.id.here
|
Jan v. |
ok
|
Mark M. |
though that might not kill you if you are still in the foreground -- you'll have to experiment with it
|
Mark M. |
usually, I kill the process from the IDE (e.g., Android Monitor tool window in Android Studio)
|
Jan v. |
how would you modularize the code? i'm thinking screen1, screen2, screen3, service, runnable_10s, runnable_30s, setup, application, and maybe test?
|
Jan v. |
with better names, of course
|
Mark M. |
um, that's well beyond what I can advise here, given that I don't know a lot about the app
|
Feb 10 | 8:20 PM |
Jan v. |
regarding gps, do you suggest rigging up a listener or get_ system call for lat/long
|
Mark M. |
um, I do not know what "get_ system call for lat/long" would mean
|
Mark M. |
if you are using LocationManager, you have no choice really but to use requestLocationUpdates()
|
Mark M. |
otherwise, the GPS radio won't turn on
|
Mark M. |
unless something else happens to be requesting location updates via GPS
|
Jan v. |
i'm stretching, but like telephony you have a pre-implemented system implementation that you conjure up and cast to (TelephonyManager)
|
Jan v. |
wait - i will look
|
Mark M. |
that would be LocationManager for locations
|
Mark M. |
it's a system service
|
Mark M. |
however, then it's not "listener or get_ system call" -- it's "listener *and* get_ system call"
|
Mark M. |
you call getSystemService() to get the LocationManager
|
Mark M. |
you call requestLocationUpdates() on the LocationManager to register the listener
|
Jan v. |
ah yes, that's it
|
Jan v. |
ok check
|
Feb 10 | 8:25 PM |
Jan v. |
Mark, thanks for all the great insights. You probably saved us a few days!
|
Mark M. |
happy to be useful
|
Jan v. |
Enough from me for now, talk to you soon :)
|
Mark M. |
OK, sounds good
|
Mark M. |
note that the chat transcript will be posted to https://commonsware.com/office-hours/ shortly after the chat ends
|
Jan v. |
Noted. Thanks!
|
Feb 10 | 8:30 PM |
Jan v. | has left the room |
Mark M. | turned off guest access |