This course will be retired on June 1, 2025.
Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
In this video we’ll see how we can use a separate Process for our PlayerService!
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
Using more than one process
isn't usually the best decision.
0:00
Adding an extra process to an app that
doesn't need it is a great way for
0:04
your app to use more resources
than it would otherwise.
0:08
If you're going to have
a multi-process app,
0:11
just make sure that you really
need that extra process.
0:14
Let's get back to our code.
0:18
We'd like to have our player
service run in a different process
0:20
than the rest of our app.
0:24
And it turns out that this
is really easy to do.
0:26
Let's open our Android manifest, and
0:29
inside our PlayerService tag,
0:34
let's add a new attribute
called android:process.
0:38
And let's set it equal to
0:44
:playerprocess, which will
be the name of the process.
0:47
Adding a colon to
the beginning of the name
0:56
tells Android that we'd like this to be
a new process private to our application.
0:59
So when we launch the app,
we should see two processes.
1:05
For me, I should see one that says,
com.teamtreehouse.musicmachine.
1:08
And one that says
com.teamtreehouse.musicmachine:playerproc-
1:14
ess.
1:20
Let's go ahead and launch the app.
1:21
And we get an error, of course.
1:30
And if we look at the error in the log,
it says, ClassCastException,
1:33
BinderProxy cannot be
cast to local binder.
1:41
And if we follow the link,
it looks like our
1:47
cast to PlayerService.LocalBinder
is what's failing.
1:51
That's weird,
1:56
we didn't do anything other than make our
PlayerService run in its own process.
1:58
And that really is all you're
supposed to have to do
2:02
to make it run in its own process.
2:05
So why did it fail here?
2:08
Well, it turns out that there's more
than one way we can bind to our service.
2:10
We can extend the binder class,
like we've done here, or
2:15
we can use a messenger object.
2:20
We could also use the Android
interface definition language, or
2:23
AIDL, but we won't talk about that option.
2:27
If our service runs in the same
process as our client,
2:30
then we can extend the binder class.
2:34
But if our service runs
in a separate process,
2:37
then we'll need to use a messenger.
2:40
So now instead of returning
a local binder and
2:43
onBind, we'll be returning a messenger.
2:46
But what is a messenger?
2:48
A messenger is just
a reference to a handler.
2:53
In fact, when we create a messenger,
we do it by passing in a handler.
2:56
But a messenger can also be transformed
into a binder, and created from a binder.
3:02
This way, we can pass our
messenger between our service and
3:08
our activity, as a binder.
3:12
Here's how it works.
3:15
First, we create a handler to handle
messages sent to our service.
3:17
Then, in our service, we create a new
messenger and pass in our handler.
3:22
Then we return this
messenger as a binder and
3:29
onBind by using the messenger
.getBinder method.
3:32
Then, an onService
connected in our activity,
3:37
we recreate our messenger
using the provided binder.
3:41
Now we can send messages by calling
the send method of our messenger and
3:45
passing in the message.
3:49
That message will then
be sent to our handler
3:52
in a separate process for handling.
3:54
So far so good.
3:58
But this only lets us send messages in
one direction, activity to service.
3:59
This is fine for playing and pausing,
but it doesn't work so well for
4:05
our isPlaying method.
4:09
We need a way for our service to
send messages back to our activity.
4:11
Luckily messages have a special
property named replyTo
4:16
which lets us send messengers
attached to our messages.
4:20
So if we want our service to be able
to send messages to our activity,
4:24
we just need to create a handler for
our activity, create a messenger using
4:28
that handler and then send that messenger
to our service using a message.
4:33
All right, we've got a way to pass
messages between our activity and
4:40
our service.
4:44
But one of the downsides
of having to use messages
4:45
is that we can no longer pass a reference
to our service to our activity.
4:48
There are only certain things
we can send across processes and
4:53
our service just isn't one of them.
4:57
We'll need to replace every instance
where our activity calls a service method
4:59
directly, by sending messages instead.
5:03
So instead of calling mPlayerService.play,
we'll be sending a message.
5:07
Here's one way this can work.
5:12
Remember that messages have two
argument parameters, arg1 and arg2.
5:15
And they're both integers.
5:20
If we associate a method with a number
we can effectively call that method
5:22
by sending a message with
its number as an argument.
5:27
So if we associate the play method with
the number zero, when the handler finds
5:32
a message with an arg1 of zero,
it will call the services play method.
5:37
And if we associate the pause method
with the number one, when the handler
5:42
finds a message with an arg1 of one,
it will call the services pause method.
5:47
The isPlaying method is
a bit more difficult
5:53
because we need to hear back from the
service after we ask if music is playing.
5:56
For this, we can assign the number
two to the isPlaying method.
6:01
And when the handler encounters an arg1 of
two it will figure out if music is playing
6:06
and send the results back to
our activity in a new message.
6:11
We're almost there.
6:16
In the next video we'll see how
to put together all the pieces
6:17
to have a working
multi-process music player.
6:21
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up