Basic android part re-Learning-re-talk about Service process Service communication
Bound ServicesQuick ViewThe bound service is allowed to be bound by other controls for interaction and inter-process communication. Once all clients are unbound, the bound service will be destroyed. Unless the service is of the started type at the same time.In this article (see the Directory) KeyService ServiceConnection IBinderExampleRemoteService LocalService
Bound is a client-server service. The bound Service allows components (such as activity) to bind, send requests, receive responses, and even perform inter-process communication (IPC ). The bound Service is generally alive only during the service period of other application components, and does not keep running in the background.
This article shows how to create a bound service, including how to bind other application components to the service. However, you should also refer to the service documentation for more information about the service, such as how to send notifications from the service, and how to set the service to run on the frontend.
Directory
- 1 Overview
- 2. Create a Bound service
- 2.1 extend the Binder class
- 2.2 Use Messenger
- 3. Bind a service
- 4. Manage Bound Service Lifecycle
|
Introduction
The bound Service is an implementation of the Service class. It allows other applications to bind and interact with it. To enable the Service to support binding, you must implement the onBind () callback method. This method returns an IBinder object that defines the programming interface required for the client to interact with the service.
Bind to a started service
As described in the service article, you can create a service that supports both started and bound. That is to say, the service can be started by calling startService (), which keeps it running, and also allows the client to bind to it by calling bindService.
If your services can indeed be started and bound, after the service is started, the system willNoDestroy the client when it is unbound from all clients. Instead, you must explicitly terminate the service by calling stopSelf () or stopService.
Although you should usually implement onBind ()OrOnStartCommand (), but sometimes both must be implemented at the same time. For example, the music player service may need to be bound to the background operation and support at the same time. In this way, the activity can start the service to play the music, and the concert continues playing. Even if the user leaves the application, it does not matter. The activity can be bound to the playback service to regain control.
Make sure that you have read # manage the lifecycle of the Bound service to obtain more information about the service lifecycle when you add a binding to the started service.
The client can bind a service by calling the bindService () method. During the call, a ServiceConnection implementation code must be provided for monitoring and service connection. BindService () returns immediately without returning the value. However, when the Android system creates a connection between the client and the service, it will call the onServiceConnected () method in ServiceConnection to pass an IBinder, and the client will use it to communicate with the service.
Multiple clients can be connected to a service at the same time. However, the system will call the onBind () method of the service to obtain IBinder only when the first client is bound. Then, the system will send the same IBinder to the client bound to the subsequent request, instead of calling onBind ().
After the last client is unbound, the system destroys the Service (unless the service is started through startService () at the same time ).
When you implement your own bound service, the most important task is to define the interface returned by the onBind () callback method. There are several ways to define the service IBinder interface. Each technology will be discussed in the subsequent sections.
Create a Bound service
When creating a service that supports binding, you must provide an IBinder as a programming interface for communication between the client and the service. There are three methods to define this type of interface:
Extension Binder class if the service is private to your application and runs in the same process as the client (this is usually the case ), you should create your interface by extending the Binder class and return an instance from onBind. The client receives the Binder object and uses it to directly access the public (public) methods available in the Binder or even Service. If your service only performs some background work for your own applications, this is the preferred technical solution. There is only one reason not to use this method to create an interface, that is, the service must be used by other applications or be used across multiple processes. If you need an interface to work across multiple processes, you can use Messenger to create an interface for the service. In this way, the service defines a Handler that responds to various Message objects. This Handler is the basis for Messenger to share the same IBinder with the client. It allows the client to send commands to the service using the Message object Message. In addition, the client can define its own Message so that the service can send messages back. This is the easiest way to execute inter-process communication (IPC), because Messenger puts all requests into a queue in an independent process, in this way, you do not have to design the service as a thread-safe mode. Use the AIDL Android Interface Definition Language (Android Interface Definition Language) to complete the following tasks: Resolve objects to the original form that can be recognized by the operating system, and serialize them across processes) to complete IPC. The previous method of using Messenger is actually based on AIDL, which uses AIDL as the underlying structure. As mentioned above, Messenger will create a queue containing all client requests in a separate process, so that the service will receive only one request each time. However, if you want your service to process multiple requests at the same time, you can directly use AIDL. In this case, your service must have multi-threaded processing capabilities and be written in a thread-safe manner. To directly use AIDL, you must create a. aidl file, which defines the programming interface. The Android SDK tool uses this file to generate an abstract class, which implements interfaces and IPC processing, and then you can extend the class in your own services.
Note:Most applicationsNoUse AIDL to create the bound service, because it may require multi-threaded processing capabilities and make the code more complex. Therefore, AIDL is not applicable to the vast majority of applications, and this article will not discuss how to use it in services. If you are sure you want to use AIDL directly, see the AIDL documentation.
Extended Binder class
If your service is only used for local applications and does not need to work across processes, you only need to implement your own Binder class, so that your client can directly access the public methods in the service.
Note:This method is useful only when the client and service are in the same application and process. For example, a music app needs to bind an activity to its own background music playing service. This method will be good.
Follow these steps:
In your Service, create a Binder instance, which implements one of the following three: including public methods that can be called by the client to return to the current Service instance, this includes public methods that can be called by the client. Or, return an instance of other classes containing the service class. The service contains public methods that can be called by the client. Return the instance of the Binder from the callback method onBind. In the client, receive the Binder in the callback method onServiceConnected () and call the bound service using the provided method.
Note:
The service and client must be in the same application to allow the client to correctly convert the objects returned by (cast) and call the object's API. The service and client must also be in the same process, because this method cannot perform any cross-process serialization operations.
For example, the following is an example of a Service. It implements a Binder to provide support for clients to access its internal methods:
PublicclassLocalServiceextendsService {
// Binder for the client
PrivatefinalIBindermBinder = newLocalBinder ();
// Generate a random number
PrivatefinalRandommGenerator = newRandom ();
/**
* Class used for client Binder.
* Knowing that this service is always running in the same process as the client, we do not need to use IPC for processing.
*/
PublicclassLocalBinderextendsBinder {
LocalServicegetService (){
// Return this instance of LocalService so clients can call public methods
ReturnLocalService. this;
}
}
@ Override
PublicIBinderonBind (Intentintent ){
ReturnmBinder;
}
/** Method for clients */
PublicintgetRandomNumber (){
ReturnmGenerator. nextInt (100 );
}
}
LocalBinder provides the getService () method for the client to return the current LocalService instance. This allows the client to call public methods in the service. For example, the client can call getRandomNumber () in the service ().
The following is an activity bound to LocalService. When you click the button, it calls getRandomNumber ():
PublicclassBindingActivityextendsActivity {
LocalServicemService;
BooleanmBound = false;
@ Override
ProtectedvoidonCreate (BundlesavedInstanceState ){
Super. onCreate (savedInstanceState );
SetContentView (R. layout. main );
}
@ Override
ProtectedvoidonStart (){
Super. onStart ();
// Bind to LocalService
Intentintent = newIntent (this, LocalService. class );
BindService (intent, mConnection, Context. BIND_AUTO_CREATE );
}
@ Override
ProtectedvoidonStop (){
Super. onStop ();
// Unbind from the service
If (mBound ){
UnbindService (mConnection );
MBound = false;
}
}
/** Called when a button is pressed (this button uses the android: onClick attribute in the layout file to associate with this method */
PublicvoidonButtonClick (Viewv ){
If (mBound ){
// Call the method in LocalService.
// However, if this call causes some operations to be suspended, the call should be carried out in a separate thread,
// Avoid reducing the activity performance.
Intnum = mService. getRandomNumber ();
Toast. makeText (this, "number:" + num, Toast. LENGTH_SHORT). show ();
}
}
/** Define the callback Method for Service binding, which is used to pass to bindService ()*/
PrivateServiceConnectionmConnection = newServiceConnection (){
@ Override
PublicvoidonServiceConnected (ComponentNameclassName,
IBinderservice ){
// We have already bound it to LocalService. We will convert the IBinder type (cast) and obtain the instance of the LocalService object.
LocalBinderbinder = (LocalBinder) service;
MService = binder. getService ();
MBound = true;
}
@ Override
PublicvoidonServiceDisconnected (ComponentNamearg0 ){
MBound = false;
}
};
}
The preceding example shows how the client binds to the service using the ServiceConnection and onServiceConnected () callback methods. The next section provides more information about the service binding process.
Note:
The above example does not explicitly unbind, but all clients should release the binding in due time (for example, when the activity suspends pause ).
For more sample code, see the LocalService. java class and LocalServiceActivities. java class in ApiDemos.
Use Messenger compared with AIDL
When you need IPC, it is easier to use Messenger than to use AIDL to implement the interface, because Messenger puts all requests that call the service into a queue. The pure AIDL interface will send these requests to the service at the same time, so that the service must be able to run in multiple threads.
For most applications, the Service does not need to run in multiple threads. Therefore, using Messenger allows the service to process only one call at a time. If your service must be run in multiple threads, you should use AIDL to define the interface.
If your service needs to communicate with a remote process, you can use a Messenger to provide the service interface. This technology allows you to implement inter-process communication (IPC) without using AIDL ).
The following describes how to use Messenger:
The Service implements a Handler, which is used to receive callbacks each time the client calls. This Handler is used to create a Messenger object (it is a reference to Handler ). This Messenger object creates an IBinder and the service returns it to the client in onBind. The client uses IBinder to instantiate Messenger (the Handler that references the service), and the client uses it to send a Message object Message to the service. Each Message in the Handler received by the Service -- specifically, it is received in the handleMessage () method.
In this way, the client does not need to call the "Method" in the service ". Instead, the client sends a "Message object", and the Service receives the Message in Handler.
The following is a simple example of a service using Messenger as an interface:
Publicclassmessential gerserviceextendsservice {
/** Command for displaying information sent to the Service */
StaticfinalintMSG_SAY_HELLO = 1;
/**
* Handler for receiving messages from the client
*/
ClassIncomingHandlerextendsHandler {
@ Override
PublicvoidhandleMessage (Messagemsg ){
Switch (msg. what ){
CaseMSG_SAY_HELLO:
Toast. makeText (getApplicationContext (), "hello! ", Toast. LENGTH_SHORT). show ();
Break;
Default:
Super. handleMessage (msg );
}
}
}
/**
* Messager published to the client for sending information to IncomingHandler
*/
FinalMessengermMessenger = newMessenger (newIncomingHandler ());
/**
* When bound to a service, we return an interface to Messager,
* Used to send messages to the service
*/
@ Override
PublicIBinderonBind (Intentintent ){
Toast. makeText (getApplicationContext (), "binding", Toast. LENGTH_SHORT). show ();
Returnmmesder. getBinder ();
}
}
Pay attention to the handleMessage () method in Handler. Here is the place where the service receives the input Message and determines the operation to be executed based on what number.
The client creates a Messenger Based on the IBinder returned by the service and sends a message using the send () method. For example, in the following example, an activity is bound to the preceding service and MSG_SAY_HELLO message is sent to the service:
PublicclassActivityMessengerextendsActivity {
/** Messenger used to communicate with the Service */
MessengermService = null;
/** Mark whether we have bound a service */
BooleanmBound;
/**
* Class for interaction with the main interface of the service
*/
PrivateServiceConnectionmConnection = newServiceConnection (){
PublicvoidonServiceConnected (ComponentNameclassName, IBinderservice ){
// This method will be called after a connection is established with the service,
// Provides the object used to interact with the service.
// We will use a Messenger to communicate with the service,
// Therefore, we obtain the client instance of the original IBinder object.
MService = newMessenger (service );
MBound = true;
}
PublicvoidonServiceDisconnected (ComponentNameclassName ){
// When the connection to the service is accidentally interrupted-that is, the service process crashes,
// This method will be called.
MService = null;
MBound = false;
}
};
PublicvoidsayHello (Viewv ){
If (! MBound) return;
// Create and send a message to the service, and use the agreed 'wh' Value
Messagemsg = Message. obtain (null, MessengerService. MSG_SAY_HELLO, 0, 0 );
Try {
MService. send (msg );
} Catch (remoteeffectione ){
E. printStackTrace ();
}
}
@ Override
ProtectedvoidonCreate (BundlesavedInstanceState ){
Super. onCreate (savedInstanceState );
SetContentView (R. layout. main );
}
@ Override
ProtectedvoidonStart (){
Super. onStart ();
// Bind to the service
BindService (newIntent (this, MessengerService. class), mConnection,
Context. BIND_AUTO_CREATE );
}
@ Override
ProtectedvoidonStop (){
Super. onStop ();
// Unbind from the service
If (mBound ){
UnbindService (mConnection );
MBound = false;
}
}
}
Note that the preceding example does not show how the service responds to the client. If you need a response from the service, you also need to create a Messenger on the client. After the client receives the onServiceConnected () callback, it sends a Message to the service. The replyTo parameter in the send () method of the Message contains the client's Messenger.
In the MessengerService. java (service) and MessengerServiceActivities. java (client) routines, you can see how to send messages in two directions.
Bind a service
Application Components (clients) can bind services by calling bindService. Then, the Android system calls the onBind () method of the service and returns an IBinder for interacting with the service.
Binding is asynchronous. BindService () will be returned immediately, andNoReturn IBinder to the client. To receive IBinder, the client must create a ServiceConnection instance and pass it to bindService (). ServiceConnection contains a callback method. The system will call this method to pass the IBinder required by the client.
Note:
Only activity, service, and content provider can be bound to the service-youNoBind a service from a broadcast receiver.
Therefore, to bind a client to a service, you must:
Implement ServiceConnection. Your implementation code must override two callback Methods: The onServiceConnected () system calls this method to pass the IBinder returned by the onBind () method of the service. OnServiceDisconnected () when the connection to the service is accidentally interrupted, for example, when the service crashes or is killed, the Android system will call this method. When the client is unbound,
NoCall this method. Call bindService () to pass in the implemented ServiceConnection. When the system calls your onServiceConnected () callback method, you can use the method defined in the interface to start calling the service. To disconnect a service, call unbindService (). When the client is destroyed, the binding to the service is also released. After interacting with the service, or when your activity enters the pause status, you should ensure that the binding is unbound so that the service can be closed in time after use. (The appropriate time for binding and unbinding will be discussed in subsequent sections .)
For example, the following code snippet connects the client to the Service created by # extension Binder class. All you need to do is to convert the returned IBinder (cast) to the LocalService class and obtain the LocalService instance:
LocalServicemService;
PrivateServiceConnectionmConnection = newServiceConnection (){
// After the connection is established with the service, it will be called
PublicvoidonServiceConnected (ComponentNameclassName, IBinderservice ){
// Because we have established a connection with a service that is obviously running in the same process,
// We can convert its IBinder into an entity class and directly access it.
LocalBinderbinder = (LocalBinder) service;
MService = binder. getService ();
MBound = true;
}
// The connection to the service will be called when the connection is accidentally interrupted
PublicvoidonServiceDisconnected (ComponentNameclassName ){
Log. e (TAG, "onServiceDisconnected ");
MBound = false;
}
};
With this ServiceConnection, the client can pass it into bindService () to complete binding with the service. For example:
Intentintent = newIntent (this, LocalService. class );
BindService (intent, mConnection, Context. BIND_AUTO_CREATE );
The first parameter of bindService () is an Intent, which clearly gives the name of the service to be bound (note that intent can be implicit ). The second parameter is the ServiceConnection object. The third parameter is a flag indicating the binding option. Usually BIND_AUTO_CREATE indicates that the service is created if the service is not started. Other possible values include BIND_DEBUG_UNBIND and BIND_NOT_FOREGROUND. Other considerations
The following are important considerations for binding services:
You should ensure that the DeadObjectException exception is captured. This exception is thrown when the connection is interrupted. This is the only exception thrown by the remote method. The reference count of an object is cross-process. You should usually bind and unbind the client in pairs and echo the start and end processes of the client lifecycle. For example, if you only need to interact with the service when your activity is visible, you should bind it in onStart () and unbind it in onStop. If your activity still receives response after stopping and entering the background, you can bind it in onCreate () and unbind it in [1. Note that this indicates that your activity needs to use the service (even in the background) throughout the runtime. Therefore, if the service is in another process, you will increase the heavyweight of the process, the process is also easy to be killed by the system.
Note:You usuallyNoYou should bind and unbind the two callback methods in the onResume () and onPause () of the activity, because the two callback methods will occur each time the lifecycle status is changed, at this time, you should minimize the processing workload. In addition, if multiple activities in the application are bound to the same service, status conversion will occur during switching between the two activities, because the current activity is unbound (during pause) then, the next activity will be bound (resume), so the service may be rebuilt immediately after destruction. (This activity state conversion and lifecycle collaboration between multiple Activities are described in the Activities document .)
For more code examples of binding services, see the RemoteService. java class in ApiDemos.
Manage Bound Service Lifecycle
Once the service is unbound from all clients, the Android system will destroy it (unless it is also using onStartCommand () started ). Therefore, if your service is a pure bound service, you do not need to manage its lifecycle-the Android system will manage it for you, depending on whether there is a client to bind it.
However, if you choose to implement the onStartCommand () callback method, you must terminate the service explicitly because the service is now consideredStarted. In this case, the service runs no matter whether a client is bound to it or not until it is terminated by stopSelf () or by other components calling stopService.
In addition, if your service is started and can be bound, you can choose to return true when the system calls your onUnbind () method. The result is that the next time the client is bound, it will receive an onRebind () call instead of an onBind () call ). OnRebind () returns void, but the client can still receive IBinder in its onServiceConnected () callback method. Figure 1 shows the running logic of this lifecycle.