Using a Separate Process6:24 with Ben Deitch
In this video we’ll see how we can use a separate Process for our PlayerService!
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 up