[MUSIC] Welcome to part three in our lesson on programming started services with messengers. After completing this part of the lesson, you'll learn how DownloadService can use a messenger to communicate back to DownloadActivity. In particular, a messenger is used to send a message from the DownloadService back to the DownloadActivity, containing the path name for the image that was retrieved and stored on a local device. We'll start by recapping how a messenger is used in the ImageDownloader app. DownloadService communicates back to DownloadActivity via a messenger. DownloadActivity creates a messenger object and uses it to encapsulate a DownloadHandler object. It then passes a reference to the messenger in an intent when it starts the DownloadService. DownloadService receives this intent via the onStartCommand method, and inside the intent is the messenger reference that's contained as an extra parameter. The ServiceHandler, which is a nested class inside of DownloadService, uses the messenger reference extra to send a path name back to the DownloadHandler. This path name indicates where on the local file system the downloaded image has been stored. Finally, the DownloadHandler receives the message that contains the path name, and it works in conjunction with the Gallery app to display the image that's retrieved and downloaded by the DownloadService. Once again, this implementation is complicated, so we explore it from several perspectives. Let's first start by talking about how Messenger is used in DownloadActivity. DownloadActivity first creates a DownloadHandler, and then it creates a messenger that encapsulates that handler. It then creates an intent that contains the reference to the messenger that's passed as an extra to the intent, and it also contains the URL for the desired image, which will be sent as a data portion of the intent. Next, the DownloadActivity calls startService, passing the intent command as a parameter. This will cross the process boundary, because the DownloadService runs in a separate process. The Android Activity Manager Service will launch the DownloadService if it's not already running. Note how the DownloadService has one thread running at this point. Let's now talk about how the messenger's used in the DownloadService. The onStartCommand in DownloadService creates a handler thread and a serviceHandler. It then goes ahead and calls sendMessage on the serviceHandler to queue the intent that was passed to it in a message. After the message containing the intent is enqueued in the message queue by the HaMeR framework, the HaMeR framework then turns around and extracts the message and calls back the handleMessage hook method on the serviceHandler. At this point, the message is used to reclaim the intent that was encapsulated in it, and the URL in the intent is used to go ahead and download the appropriate image, stored on the local file system, and then it uses the messenger reference that's stored in the intent, in order to be able to return the path name for that stored image file back to the DownloadActivity. Note how a messenger is needed here to cross the process boundary, because you can't call sendMessage and handleMessage on handlers that are in different processes. Finally, the DownloadHandler's handleMessage hook method is dispatched by the HaMeR framework running in the DownloadActivity, and that's used to actually display the image in conjunction with an activity from the Gallery app. We'll now walk through the first part of the implementation of the ImageDownloader app's messenger-related code. In particular, we first walk through how the DownloadService replies to the DownloadActivity, like calling the send method on the messenger reference that was passed to it. The DownloadService uses the nested ServiceHandler class to actually send this reply message. And we'll take a look at the source file, DownloadService.java, that's available at this link. We're now back inside the Android Studio project file, looking at the implementation of ServiceHandler, which is the inner class that's nested inside of DownloadService, that inherits from Handler, and it uses its handleMessage hook method to process messages that are sent to it from onStartCommand. These messages of course indicate which images to download. If you take a look here, you can see the constructor for serviceHandler is passed a looper. The serviceHandler is created in the onCreate hook method when the service is first launched. And the looper here is actually the looper that's associated with the handler thread, and the ServiceHandler uses this to ensure that its handleMessage hook method is actually run in the handler thread's background thread. Down here we see the implementation of makeDownloadMessage, which is called by onStartCommand when it gets an intent and a startId. MakeDownloadMessage as you can see uses the obtained factory method for message to make a message. It then goes ahead and it stores the intent in the obj field of the message, and the startId in the arg1 field of the message, and then it returns the message. Down here we see the implementation of a handleMessage. handleMessage of course is what's called back in the background thread of the serviceHandler. This takes the message, fishes out the intent it was passed in, then goes ahead and uses the data field of that intent to download a given URL at the web server, using the downloadImage helper method. And once the image has been downloaded and stored by the downloadImage file, the URI to the path name to this stored image is then going to be sent back to the client by calling the sendPath method, which takes the intent, which contains the messenger reference, as well as the URI to the path name of the downloaded file. Here you can see the call stopSelf, as we talked about before, that implements the Concurrent Service Stopping Idiom. Let's now go down here and take a look at the sendPath helper method. This takes the intent that was passed in originally and the path name, it extracts the reference to the messager from the intent via getExtras, it then goes ahead and calls a factory method called makeReplyMessage. We'll look at that in just a second. That gets a message to send back to the DownloadActivity, and then finally it goes ahead and it sends that message back to the activity by calling send on the messenger reference that was fished out of the intent. Here is the makeReplyMessage implementation. As you can see, it goes ahead and gets a message. It then creates a bundle that will be used to store the path name to the downloaded image. In other words, where it resides in the local file system. This is stored in a bundle. That bundle is set as the data for the message, and then we set the arg1 field of the message, it could be either RESULT_OK if everything worked fine, or RESULT_CANCELLED if it failed to download for some reason. And then we go ahead and return the message back. So, that will then of course be used to get the message that it sent back to the client. There's just a couple of other methods here. We'll take a quick look at the getPathname message. getPathname is used by the client activity to extract out the string from the message that represents the path name to the downloaded image. Next, we'll show the second part of the implementation of the ImageDownloader app's messenger-related code. We'll now walk through how the DownloadActivity receives the message containing the path name to the downloaded image via the DownloadHandler in the app's user interface thread. Note how the Android's Binder IPC and HaMer frameworks are used to deliver these messages across process boundaries. We're now back inside the Android Studio project looking at the implementation of DownloadHandler, which is a class that's nested inside of DownloadActivity. This class inherits from Handler, and its handleMessage method is used to process messages sent to it from the DownloadService. These messages of course contain the path name to images that have been downloaded. You can see it has one field called mActivity, which is a WeakReference that allows the activity to be garbage collected properly. Down here, the constructor of this class simply creates a new WeakReference instance and stores it in the local field. All the real heavy lifting of this class is done in its handleMessage method. handleMessage is passed the message containing the path name, where to find the image that's been downloaded. We first check to see if the activity has gone away. If so, we bail out, because there's nothing we can do, since our surrounding activity has gone away. We then use the getPathname helper method from DownloadService to extract the path name from the message. If the path name is null, then something went wrong with the download, so we go ahead and show a dialog saying that we failed to download the image that was requested. In either case, we then dismiss the progress dialog, so that stops. We then go down here and we call the makeGalleryIntent factory method. And that creates an intent that'll be used to launch the Gallery app, passing it a path to the downloaded image fall to display. So once we get this intent, we go ahead and start the Gallery app image viewer to display the intent that was downloaded. And the last thing we do here is we set the process button click field of the activity to true, indicating that the user can then go ahead and add in new URLs for what they want to download, new images to download. Note that the handleMessage method runs in the user interface thread. So this is a very quick operation. Its main purpose in life really is to do some sanity checking and then to go ahead and launch another activity to actually display the results of the download. This concludes part three of our lesson on programming started services with messengers. [MUSIC]