The actions you execute in an intent service can be long running, since the service is decoupled from the user interface, and it’s running in its own background thread. But that also means you don’t have direct access to the current activity, and can’t call the activity’s methods directly or affect any of its view components. The most common way of sending information back to the UI is to use broadcast messages.
- [Narrator] The actions you execute in an intents service can be long running, since the service is decoupled from the user interface, and it's running in its own background thread. But that also means that you don't have direct access to the current activity, and you can't call the activity's methods directly, or affect any of its view components. The most common way of sending information back to the UI, is with broadcast messages, and specifically, you can use local broadcast messages. These run in the same process as the rest of the app, and aren't visible to other apps or processes on the same device.
I'll start in my service, where I already have code in place to execute some code in the background. I'll find that code down here in the handle action fu method. Now, I'm going to be sending a number of different messages, so I'll add a new custom method at the bottom of the class. It'll return void, and it'll be called send message, and it'll just accept a single string that I'll call message. The first step to sending a message back to the UI, is to create an intent object.
The intent object should be created with the instructor that accepts a single string. That's called the action parameter. I'll give it an action name of service message, and then I'll turn that into a constant so it can be used elsewhere in the application. I'll come up here, and I'll make sure that that constant is public, so it can be used everywhere. Next, I'll come back down here to my send message method, and I'll add some information to the message.
I'll call it intent.putextra, and I'll pass in a string, that will be the extra key, and then I'll pass in the value, which is the message string. And I'll come back here, and I'll turn that into a constant as well, and I'll call this one message underscore key. Now I'm ready to actually send a message. I'm going to use a class called local broadcast manager. This class has a method called get instants, that accepts a context.
You can pass in this for the service, or more commonly, you can pass in get application context. Then from there, call the send broadcast method, and pass in the intent object. And that's all you need to do to send the message. You're not seeing who the message is being sent to, you're broadcasting it out to the entire application, and any activity or fragment can be listening for that message to be received. I'll set up my main activity to receive and react to the message.
First, I'll add a field up to the top of the class, and this will be an instance of the class broadcast receiver. I'll call it M receiver, and I'll create it with new broadcast receiver. That automatically expands to include a single method called on receive. This method receives the context and the intent object, and that's going to be the intent that I just sent from the service. I'll create a string variable that I'll call message here, and then I'll look at the intent object and call get string extra, and pass in the constant from my intent service, message key.
And then I'll call my log method, and I'll display the message that was received. Now this code is going to be running on the main thread, and so it will have access to the entire activity, and all of its view hierarchy. In order for this receiver to actually receive the messages, you have to register it. The most common place to do that is on the on start method, that will be executed automatically as the activity comes to the screen. I'll override that method, and after the super class is called to on start, I'll use the local broadcast manager class, again.
Once again, I'll call get instants, and pass in get application context, and from there I'll call register receiver. This method takes two arguments. The first is the receiver object that implements the on receive method, and the next is an intent filter. I'll create that with the constructor, and I'll use the version of the constructor that receives a single string, the action, and I'll pass in the constant that I declared in the service, with myintentsservice.servicemessage.
I'll add some line feeds in there so it's a little bit easier to read. Now to ensure that you don't have resource leaks, you also need to deregister the receiver. I registered it in the on start method, so I'll deregister it on the on stop method. This code is very similar, and I'll start by just copying this bit, local broadcast manager.getintents.getapplicationcontext, but then I'll call unregister receiver, and once again pass in the receiver object.
If you have more than one type of message that you're listening for, you can call the register receiver method as many times as you need, but you only need to call unregister receiver once. Finally, I'll go back to my intents service, and I'll find all the places where I'm using log.i. I'll select this bit of code and copy it to the clipboard, and then I'll press control R on Windows or command R on Mac to open search and replace. I'll paste that string in, and I'll replace it with a call to send message, and I'll replace all.
So now, instead of using log cat directly from the service, I'm sending information back to the user interface, and I'll see the message displayed in the UI, and I'll run the app and test this. I'll clear my output, and click run code, and I see all the messages now coming from the service, being sent to the user interface in broadcast messages, and then being displayed in the text field. The intent object that you send in a broadcast message can contain anything that works as an intent extra, that includes nearly all primitive types and arrays of those types, and for more complex objects, you can implement the parsable interface, so for example you can send back arrays of instances of a pojo class, where each instance of the class contains a data object.
Just as with the a-sync class, there's only one thread allocated to running intents services in a particular app, so if you send multiple requests, they'll be queued up and then run one at a time. This can be useful if for example, you want to download multiple files from a remote server. You simply issue the requests all at the same time, and then the one and only background thread that's available to intents services will be managed for you.
First, discover how to create and start simple background threads, and how to use handlers to manage a thread's message queue. Then, learn various methods for optimizing the scheduling and performance of background tasks in Android with AsyncTask, intent services, and the JobScheduler API. Plus, explore tools that help you implement multithreading for different tasks in Android: Loader, for asynchronous data loading, and the open-source API Retrofit, for making HTTP requests.
Note: To get the most out of this course, you should be comfortable programming with Java, and should understand the most basic skills that are needed to build Android apps with the Android SDK and Android Studio.
- Creating and running a background thread
- Sending messages to the UI from threads
- Managing multiple background threads
- Managing threads with AsyncTask
- Managing long-running tasks with services
- Scheduling background tasks with JobScheduler
- Using other APIs for concurrent programming