Nov 30 | 3:50 PM |
Mark M. | has entered the room |
Nov 30 | 3:55 PM |
Mark M. | turned on guest access |
Nov 30 | 4:00 PM |
Steve | has entered the room |
Steve |
Hey Mark!
|
Mark M. |
hello, Steve!
|
Mark M. |
how can I help you today?
|
Steve |
I actually saw you at the droid con in NYC :) Nice talk
|
Mark M. |
thanks!
|
Steve |
I am having an issue with AsyncTasks
|
Steve |
View paste
|
Mark M. |
isn't everyone? :-)
|
Steve |
Lol :P
|
Steve |
Is this actually a problem? Am I doing something wrong by having to call execute() before get()?
|
Mark M. |
OK, let's take this from the end and work backwards
|
Mark M. |
there is no point in having this on a worker thread in your current implementation
|
Mark M. |
as get() is a blocking call, and so it ties up whatever thread you're on
|
Mark M. |
and I assume that's the main application thread.
|
Steve |
Right
|
Mark M. |
you would get the same basic results by extracting the code from doInBackground() and calling it directly
|
Steve |
Currently this is all happening within an IntentService, on a worker thread
|
Mark M. |
wait
|
Mark M. |
you're having an IntentService execute an AsyncTask?
|
Mark M. |
if so, why? you're already on a background thread; another background thread won't make the work background-er
|
Nov 30 | 4:05 PM |
Steve |
Yeah, but we essentially do not need this AsyncTask to create a new thread.
|
Nov 30 | 4:05 PM |
Mark M. |
so, get rid of the AsyncTask
|
Steve |
We only want to use this custom AsyncTask that we use for all networking operation to add extra data/params when calling our endpoints
|
Mark M. |
most likely, "all networking operation" shouldn't *be* an AsyncTask, but be something *used* by an AsyncTask
|
Mark M. |
that way, that logic can also be used without an AsyncTask, such as by your IntentService
|
Steve |
100% agreed
|
Steve |
I just don't know if a refactor is in the question right now :P
|
Mark M. |
personally, I have never called get() on an AsyncTask, as I break out in hives just thinking about it
|
Mark M. |
I wouldn't expect a TimeoutException, though
|
Steve |
Hahaha
|
Steve |
get() essentially does not call doInBackground
|
Steve |
I assumed it would just call doInBackground() on the calling thread
|
Mark M. |
:: shrug ::
|
Mark M. |
no
|
Mark M. |
it should block the current thread waiting for the background thread to complete
|
Mark M. |
remember, you called execute(), so that's kicking off the background thread
|
Steve |
Ah got it
|
Mark M. |
by the time you call get(), that background thread's already chugging along
|
Steve |
That makes WAY more sense
|
Mark M. |
now, I suspect that get() is... under-tested by Google, so it's possible that they introduced a bug somewhere along the line
|
Steve |
And makes get() sound more useless :P
|
Nov 30 | 4:10 PM |
Mark M. |
well, it fits your need, as I understand it -- blocking until the work is completed
|
Mark M. |
it just still involves a background thread
|
Mark M. |
but, you could just call doInBackground() yourself directly
|
Steve |
Yeah
|
Mark M. |
replace the execute().get() with doInBackground() (followed by onPostExecute(), if you need that work too)
|
Mark M. |
it wouldn't pass one of my code reviews, but, then again, I'm a harsh grader
|
Mark M. |
:-)
|
Steve |
It hurts me to think of doing that lol
|
Steve |
We need to decouple the AsyncTasks from this logic at some point anyways :P
|
Mark M. |
right
|
Steve |
I'll take this back and see what the team thinks
|
Steve |
Thanks for your help!
|
Mark M. |
you're welcome!
|
Steve |
Have a good one
|
Steve |
Bye
|
Mark M. |
see ya!
|
Nov 30 | 4:20 PM |
Steve S. | has entered the room |
Mark M. |
hello, Steve S!
|
Steve S. |
HI Mark!
|
Mark M. |
the S-less Steve had some questions earlier but (AFAIK) is done at the moment
|
Nov 30 | 4:25 PM |
Mark M. |
so, it's your turn -- do you have a question?
|
Steve S. |
sure. I'll paste in my question:
|
Steve S. |
I'm trying to better understand how to use synchronization. Is closing a Bluetooth socket in a synchronized block something I should avoid?
|
Mark M. |
um, I can't really answer that in the abstract
|
Steve S. |
ok
|
Mark M. |
what else is going on in the block?
|
Steve S. |
here's the block:
|
Steve S. | |
Steve S. |
This is used to cancel a read operation, which is blocking.
|
Mark M. |
is close(mmSocket) doing much other than calling close() on the BluetoothSocket?
|
Steve S. |
sorry - that's basically all that it's doing
|
Mark M. |
is there anything else synchronizing on LOCK?
|
Steve S. |
yes, there are about five other places where that's done
|
Mark M. |
and some of this stuff might be called on different threads?
|
Nov 30 | 4:30 PM |
Steve S. |
yes - that's why i'm doing it
|
Steve | has left the room |
Mark M. |
then probably you should be synchronizing by one means or another
|
Steve S. |
ok
|
Mark M. |
it's tough to say without a deeper look at the code
|
Steve S. |
sure
|
Mark M. |
plus, my BluetoothSocket experience is limited (though it may increase here in the coming weeks)
|
Mark M. |
if the only thing was mmIsCanceled, you could switch to an AtomicBoolean for that
|
Steve S. |
i don't think that's an option in this case (i haven't shown you all the code...)
|
Mark M. |
I guessed as mch
|
Mark M. |
er, much
|
Steve S. |
because some of the synchronized blocks are executed on the main thread, i assume i shouldn't include any potentially long-running operation in the synchronized blocks, like opening a connection
|
Steve S. |
i was wondering if that would also be true of closing a connection
|
Mark M. |
I have no idea how fast that is
|
Mark M. |
my gut instinct would say it's cheap
|
Mark M. |
usually, there isn't much handshaking on a disconnect in communications protocols, as there's no guarantee that a formal disconnect will ever happen
|
Mark M. |
but, you'll need to do some performance analysis to see how quick it is in practice
|
Nov 30 | 4:35 PM |
Mark M. |
if it is sub-millisecond, don't worry about it
|
Steve S. |
ok. i have done some timings, and i think the close operation takes about 3 ms
|
Mark M. |
well, the per-frame budget is 16ms
|
Mark M. |
on the one hand, 3 is quite a bit smaller than 16
|
Mark M. |
on the other hand, there's other work to be done in the frame
|
Mark M. |
if you don't mind the occasional frame drop on a close(), then don't worry about it
|
Steve S. |
ok
|
Mark M. |
for most frames with close(), the 3ms won't push you over budget, but occasionally it will
|
Mark M. |
one of those probability things
|
Steve S. |
regarding the 16ms budget: is that how long i have to do something on the main thread before returning control to the OS?
|
Mark M. |
it's more that the UI updates, in a widget-based UI, are locked to a 60fps cycle
|
Steve S. |
ok
|
Mark M. |
so, every 16.666666666666666666ms, Android takes whatever has been updated in the buffer and blits it to the screen
|
Mark M. |
(note: that number needs more 6's)
|
Steve S. |
right!
|
Mark M. |
if you take up too much time, nothing gets updated in the buffer, and so the UI does not change on that frame cycle
|
Steve S. |
ok
|
Mark M. |
now, it's entirely possible that nothing would change anyway, as the UI may not be drawing anything right then
|
Mark M. |
but the drawing work is done by the framework on the main application thread
|
Mark M. |
which is why we want all of our callbacks from the framework to our code to be cheap
|
Mark M. |
because there might be a lot of them (e.g., getView() calls on a ListAdapter while scrolling)
|
Nov 30 | 4:40 PM |
Steve S. |
sure
|
Mark M. |
in your case, close() isn't going to be called in a loop or other frequent cases, most likely
|
Steve S. |
right
|
Mark M. |
which means the odds are decent that the 3ms won't cause any particular problems
|
Mark M. |
but, every now and then, something big might be happening in the UI when you decide to call close()
|
Mark M. |
and if some animation (e.g., scrolling) doesn't update because of a dropped frame, you have a bit of jank
|
Mark M. |
some people are very sensitive to jank -- I'm not one of them
|
Mark M. |
an app can drop a fair number of frames before I start to notice
|
Mark M. |
now, if close() were 30ms or 300ms, there's no debate: get that off the main application thread
|
Mark M. |
and if it were 0.3ms, there's probably no debate: just don't worry about it
|
Steve S. |
ok. so it sounds like i could get a better sense of whether it's ok to close the socket in a synchronized block by timing it, and as long as it doesn't add too much time, it would be ok
|
Mark M. |
3ms is a tweener value
|
Mark M. |
yup
|
Steve S. |
cool. i'll do some more careful timings then
|
Steve S. |
no more questions today - thank you for your help!
|
Mark M. |
you're welcome!
|
Steve S. |
have a great rest of the day!
|
Mark M. |
now, I just need a third Steve to show up in the next 15 minutes, and I hit the trifecta!
|
Nov 30 | 4:45 PM |
Steve S. |
based on my experience, that shouldn't be all the unlikely
|
Steve S. | has left the room |
Nov 30 | 4:55 PM |
Mark M. | turned off guest access |