As much as we'd like to focus on creating and managing
threads and work packets, we tend
to ignore the biggest, hardest problem in threading, memory.
My name is Colt McAnlis.
And while threading and memory have
a long, complicated history in programming,
there are some specific nuances on Android
that you need to be aware of.
You gotta remember that memory in computing
isn't really thread safe.
When two threads are operating on the same block of memory,
weird things happen.
I mean, you can get memory contention problems with read
write access order, ABA problems,
rips in the fabric of space time.
OK, maybe not-- maybe not the last one.
But anyhow, fixing these means restricting memory access
from threads using locking, which is a whole separate video
series that we're not going to get into right now.
But most important to understand is that Android
isn't immune to these problems.
For the most part, the same techniques
you use to deal with these issues on other platforms
can be applied here, too.
But there are a few specific cases
that you need to be aware of.
Let's start with the fact that by design, UI objects are not
thread safe.
UI objects are expected to be created, used,
and destroyed all on the UI thread,
and not guaranteed to behave properly on any other threads.
Trying to modify or even reference them on other threads
can throw exceptions, cause silent failures, crashes,
and just general weirdness.
In fact, just holding a direct reference to a UI object
on a worker thread can be a problem.
For example, your work object may contain a reference
to a view.
But before your work completes on the worker thread,
the view is removed from the view
hierarchy on the main thread.
So what do you do here?
I mean, you can't trust any of the properties of that view
since the data has changed.
And updating those properties doesn't really
mean anything, since it's not part of the hierarchy anymore
and won't be drawn to the screen.
And this gets crazy really quick.
Now remember, views contain references
to their owning activity.
I mean, we did a whole video on how leaking those views
can cause all sorts of memory problems.
But this gets even worse when threading is involved.
If an activity is destroyed but there still
exists a threaded block of work that references it,
the activity won't get collected until that work finishes.
So if you kick off some work and the user rotates the screen
three times in a row before that work completes,
you could end up with three instances of that activity
object resident in memory.
And to be clear, it's not just explicit references
to UI objects that you need to worry about.
You also have to be cautious of implicit references, as well.
Check out this very common seen-all-the-time coding
pattern in Android apps.
You've got some threading object that's
declared as an inner class of an activity.
The problem here is that the async task object
now has an implicit reference to the enclosing activity
and will keep that reference until the work
object has been destroyed.
The result is the same problem.
Until this work completes, the activity
stays around in memory.
And by the way, this type of pattern
also leads to common types of crashes seen in Android apps.
Some block of threading work has kicked off.
But the user hits Back or does something else to change
the top-most activity.
Later, when the threaded work completes,
it tries to make updates to a state that's no longer valid.
The result is a dialog box notifying me
that an app I haven't used for 10 minutes has crashed,
which is kind of awkward for everybody.
The takeaway here is that you shouldn't hold references
to any types of UI specific objects
in any of your threading scenarios, which
leads to the natural question, how
are we supposed to update the UI from threaded work.
The trick here is to force the top level activity
or fragments to be the sole system responsible for updating
the UI objects.
For example, when you'd like to kick off some work,
create a work record that pairs a view with some update
function.
When that block of work is finished,
it submits the results back to the activity using an intent
or a run on UI thread call.
The activity can then call the update function
with the new information, or if the view isn't there,
just drop the work altogether.
And if the activity that issued the work was destroyed,
then the new activity won't have a reference to any of this
and will just drop the work too.
See?
No crashes, no memory leaks, just pure clean fun.
Now, if you ever want a deeper look
at how threading and memory are working together,
make sure to check out the powerful new tools
inside of Android Studio, which just got an awesome revamp
as a version 2.0.
The deeper you go into Android performance,
the more you realize how important
memory is on this platform, which
is why you should check out the rest of the memory videos
on the Android Performance Patterns playlists.
And don't forget to check out our Google+ community as well.
So keep calm, profile your code, and always remember,
perf matters.
[MUSIC PLAYING]