Office Hours — Today, June 13

Tuesday, June 11

Jun 13
9:55 AM
Mark M.
has entered the room
Mark M.
turned on guest access
10:00 AM
bbarnes
has entered the room
Mark M.
hello, bbarnes
how can I help you today?
bbarnes
Hi!
I took your advanced course in NYC last summer
I have a question regarding Android Services
That is, with a started service
10:05 AM
Mark M.
go ahead
bbarnes
If the app is going to communicate with the service on an ongoing basis
Does it seem right to pass data to the service by calling startService over and over with Intents?
Mark M.
seems fine to me
bbarnes
The original call will indeed start the service, and further calls will just pass the intent
Okay, thats good
It seemed like a questionable design, just because of that fact that "START service" would be called potentially many times
and frequently
Mark M.
it's not the best method name
however, as I probably said many times in training, "they didn't ask me"... :-)
bbarnes
What are the best practices for communicating with services?
Mark M.
that's a bit difficult to answer in the abstract
10:10 AM
Mark M.
can you be more specific?
bbarnes
As far as our application of services...our app will be communicating with and controlling a physical system that controls lights/shades/etc
The service was intended to facilitate the communication with the system itself
that way if we wanted to reuse that framework for another app, widget, etc they could all just use the same communication service
so now we
we're* looking at how to best pass the data back and forth between the app and the service that will be maintaining the connection to the system
the connection being a TCP connection
Mark M.
you have multiple options
I would first focus on how you are going to get the data from the service back to the UI or other portions of your app
personally, I would use something along the lines of an event bus: LocalBroadcastManager, Otto, greenrobot's EventBus, etc.
however, that assumes that the data coming down the TCP connection is a bit "transactional" and can be represented in discrete objects, versus some sort of stream
bbarnes
The current proposal was that the service would communicate system update back to a DAO layer that the UI would observe
Mark M.
you could do that too
whether that's via a ContentProvider and ContentObservers, or a POJO-based DAO layer with an event bus, or whatever
10:15 AM
bbarnes
yeah it's all transactional in the way that it would be commands from the app thru the service and out to the system, and then responses to those commands or independent status updates from the system back to the app
Mark M.
once you have the service->rest of app communication mechanism decided, you can determine if you want to use that same mechanism to control the service, or something else
so, for example, if you're using a flexible message bus, you could send commands to the service via bus messages, versus startService()
advantage being greater communications parallelism
disadvantage perhaps being figuring out where to startService() the first time
bbarnes
could you elaborate on the bus messages? that sounds more ideal for our application than the startservice
Mark M.
personally, I've used LocalBroadcastManager and Otto
LocalBroadcastManager is in the Android Support package
bbarnes
start service for the first time would be easy on our end because we have a process for intially connecting to a system already in the flow of the app
Mark M.
pros: reuses the same BrroadcastReceiver/IntentFilter stuff you may be used to
cons: limits you to the same BroadcastReceiver/IntentFilter stuff
bbarnes
awesome, we definitely didnt consider that before
Mark M.
Otto is from Square
third-party Apache-licensed library
pros: much more flexible event model, with whatever event object you want, and simple annotations for denoting what methods receive the events
cons: it's a third-party library
I know of, but have not used, greenrobot's EventBus: https://github.com/greenrobot/EventBus
their site lists pros/cons vs. Otto
Julien
has entered the room
bbarnes
Great, checking out the link
Mark M.
LocalBroadcastManager has some coverage in the book already, and I'll be adding a chapter profiling all of these in the next update ort wo
er, or two
let me take a question from Julien, and I'll be back with you in a bit
10:20 AM
Mark M.
julien: hi! do you have a question?
10:20 AM
bbarnes
Sure, thanks
Julien
hi yes
Mark M.
Julien: go ahead
Julien
I have a list with severals items (cover of books). You can start download of each one (i'm using DownloadManager), i would like to display the progress of each download (10% for instance) directly in the row view
I'm looking for the best architecture
to query at regular time the DownloadManager
and update the views
10:25 AM
Mark M.
um
in a UI, postDelayed() is the lightest-weight means of doing loose timing
so you could set up a postDelayed() "loop" to get control every so often
each pass, you would call query() on DownloadManager with a suitable DownloadManager.Request
you would use the resulting Cursor to pick out the COLUMN_TOTAL_SIZE_BYTES and COLUMN_BYTES_DOWNLOADED_SO_FAR
compute your percentage based upon those
at that point, how you update the UI depends a bit on what the UI is
is the "row view" in a ListView? A TableLayout? something else?
Julien
ListView with a BaseAdapter
Mark M.
OK
once you know the new percentage, you would update the data model behind the BaseAdapter, to handle scrolling
plus, you would see if the row for this download is visible in the ListView, get at the row in the ListView itself using typical ViewGroup methods, and update it
Julien
ok I see, it's better than calling notifyDataSetChanged each second i guess
Mark M.
ListView has getFirstVisiblePosition() and getLastVisiblePosition() to help you determine if your row is visible
10:30 AM
Mark M.
yeah, notifyDataSetChanged() tends to be a bit invasive
that's simpler, and if your UI will work with it, go that route
my assumption was that notifyDataSetChanged() would cause too much of an update, and therefore manually fiddling with each row is more apropos
Julien
yes
Mark M.
what trips up developers doing this is forgetting that the user *can* scroll, so you still need to do all the ListView/ListAdapter stuff right for updating the percentage in getView()
let me switch back to bbarnes, and I'll be back with you shortly
Julien
ok
Mark M.
bbarnes: do you have another question?
bbarnes
Well, I think we got the main question answered
I do just want to run this by you though
The potential design would now look like this: App uses bus to send and receive messages with the connection service
Then the app is in control of updating the backend as we see fit, and the UI can still observe that as planned
So the service would solely be there to maintain the connection with our system via a REST interface
Anything look out of whack?
Mark M.
"maintain the connection" = always-connected socket?
bbarnes
correct
10:35 AM
Mark M.
and that's what your server needs?
I'm confused as to where the REST interface comes into play
bbarnes
As per the current design as far as I know
Mark M.
as that's usually reserved for stateless HTTP
but, other than that, what you have sounds fine
bbarnes
I actually am not very well versed in the REST protocol we are making, so thats the next thing we will investigate
Maybe the connection can come and go
Mark M.
the other thing is to make sure that you have a clear idea when you will call stopService()
bbarnes
But right, either way the service's job will be to keep some connection available
Oh right!!
I almost forgot
The plan for when to call that was in onDestroy of the first activity launched
Are we violating any best practices by doing that?
Mark M.
that's not an ideal plan, as if the user presses HOME, your service stays running
you have two major options, as I see it
1. if you determine that you are doing REST-over-HTTP and do not need a persistent connection, switch to using an IntentService and sending commands via startService(), as IntentService knows to shut down when there is no more work queued up
2. Attempt to use onUserLeaveHint() to figure out that the app is going into the background, call stopService() then... and then figure out when startService() will be needed in the future (e.g., check some boolean before sending any messages)
10:40 AM
bbarnes
Okay - the thought was that if the user presses home, they can come back into the app and have no connection delay
Ive never heard of onUserLeaveHint - sounds pretty useful!
Mark M.
the docs around it are a bit wishy-washy, which is why I haven't written about it
it's a callback method on Activity
"Called as part of the activity lifecycle when an activity is about to go into the background as the result of user choice. For example, when the user presses the Home key, onUserLeaveHint() will be called, but when an incoming phone call causes the in-call Activity to be automatically brought to the foreground, onUserLeaveHint() will not be called on the activity being interrupted. "
bbarnes
Huh, since api 3
Mark M.
is this an app for ordinary end users, or is this an in-house enterprise app?
bbarnes
Definitely end users
Mark M.
yeah, then, you really don't want to leave the service hang out forever
bbarnes
Wouldnt the process get killed after awhile though?
Mark M.
sure, but processes with a service in them live longer, generally speaking, than processes sans service
so, the user runs your app, then goes into Angry Birds, then takes a phone call, and returns from the phone call to see that Angry Birds has to start back up at the beginning, because it got killed rather than your process
*eventually*, even a service-laden process will be terminated due to low memory conditions
the key is device behavior in the meantime
bbarnes
Alright, thanks
10:45 AM
Mark M.
unless that service is adding value while the app is in the background, you really want to figure out a point when you can stop it
let me switch back to Julien
bbarnes
Is there another good way to leave it running for a certain amount of time?
Mark M.
Julien: do you have another question?
bbarnes
Sure
Julien
View paste
Could you be more specific on the postDelayed() "loop" which get the progress of downloads ? 
Where would you put this loop, in a Service maybe ?
Mark M.
no, in the activity with the ListView
Julien
ok
Mark M.
you only need to update the ListView while you have a ListView :-)
Julien
Do you think it's ok having it running during the life of this activity ?
or should i managed to handle start and stop
?
Mark M.
so long as your delay period isn't insane, sure
oh, I see
yeah, onStart()/onStop() is probably a good idea
use removeCallbacks() in onStop() to break the "loop"
here I use onResume()/onPause(), but onStart()/onStop() would work as well
Julien
ok
10:50 AM
Julien
so in my loop i need to query the DownloadManager and update the visible row with progress
if any
Mark M.
yes
Julien
And in getView
Mark M.
yes
Julien
why in getView ?
If i got my loop
updating
the row ?
Mark M.
if the user scrolls, you want to show the percentage of the newly-populated rows
that percentage has to come from somewhere
Julien
from the loop ?
Mark M.
you could say that you'll show nothing, until the next pass of the postDelayed() loop
but you want that loop to be slow (every few seconds)
Julien
ok just to have a smooth UI
i get it
Mark M.
right
Julien
Thanks, no more question for now
Mark M.
bbarnes: you asked "Is there another good way to leave it running for a certain amount of time?"
you are welcome to cook up your own sort of inactivity timer in the service
i.e., if nothing has happened in X seconds, go ahead and tear things down
the key is whether you can determine a reasonable value of X, then deal with the somewhat non-deterministic state when you come back to the foreground
bbarnes
OK
Mark M.
should all be doable, but will require a bit more thinking
bbarnes
Are there any metrics/rules of thumb for that?
Mark M.
none that I can cite
bbarnes
...any that you cant? ;)
10:55 AM
Mark M.
sure: pick a value of X that will piss off the fewest users
"-)
er, :-)
bbarnes
Gotcha
Well this was really useful, I imagine we will be back for other office hours
Thanks for your time
Mark M.
you are very welcome
note that the transcript from this chat will be archived at http://commonsware.com/office-hours/ shortly after the chat ends
the next chat is Tuesday, 4pm Eastern
any final questions?
bbarnes
I answered that myself, but there is a final question - where should I report that?
Mark M.
this is unique to the HTC One, in your tests?
bbarnes
As far as I know
Mark M.
I think HTC may be monitoring the 'htc' tag, but I'll pass the link along to one of my HTC contacts to make sure they see it
bbarnes
My Droid DNA was alright
11:00 AM
bbarnes
thanks - Ill add that tag
Mark M.
you already have it, I think
yeah, it's there
bbarnes
ah, right
Mark M.
well, that's a wrap for today's chat
bbarnes
great
Mark M.
have a pleasant day, all!
bbarnes
has left the room
Julien
has left the room
Mark M.
turned off guest access

Tuesday, June 11

 

Office Hours

People in this transcript

  • bbarnes
  • Julien
  • Mark Murphy