There are two main ways to use service in Android, by invoking the StartService method of the context, or by invoking the Bindservice method of the context, this article only explores the use of pure bindservice, Does not involve any StartService method calls. If you want to know about the use of StartService, see Overview of basic usage of StartService in Android.
Features of Bindservice startup service
A service that starts with the StartService boot Service,bindservice has the following characteristics:
1. The service initiated by Bindservice is a typical client-server interface between the caller and the service, that is, the caller is the client, the service is the server, the services are one, However, a connection bound to the client above the service can be one or more. Specifically, the client referred to here refers to a component, such as an activity.
2. Client-side (that is, one party to the call Bindservice, such as an activity) can obtain an instance of the service through the IBinder interface, thus enabling a method to invoke the service directly on the client side to enable flexible interaction. And the client-server interaction across processes can be implemented with IBinder, which is not possible in pure StartService-initiated service.
3. Unlike StartService-initiated services, the default is performed indefinitely (you can stop running via the context's StopService or service Stopself method), The lifecycle of a bindservice-initiated service is closely related to the client it binds to. When the client is destroyed, the client is automatically unbound from the service, and of course the client can unbind the service by explicitly invoking the Unbindservice method of the context. When no client is bound to the service, the service destroys itself (except when it is started by StartService).
4. The callback methods executed by StartService and Bindservice are different: The service initiated by StartService will involve the Onstartcommand callback method of the service. Services initiated through Bindservice will involve callback methods such as service Onbind, Onunbind, and so on.
Bindservice code Example
The use of Bindservice is mainly divided into two scenarios:
1. Service caller client and service in the same app;
2. The caller client of the service is an activity in the APP1, and the service is a App2 of service,client and service in the two app, which is primarily used to implement communication across processes.
For the sake of simplicity, this article only discusses the first scenario where the service caller client and service are in the same app, which is the case that we use most in actual development. If you want to know how to communicate with the service through the Bindservice in two different processes, see the other blog, "Android with Messenger and service," to achieve two-way communication between processes.
Let's use an example to illustrate the basic usage flow of bindservice in the first case.
First we have a testservice, which inherits from the service, which is the server side of the Client-server interface. We have included output statements in its major lifecycle callback methods. The Testservice code is as follows:
Package Com.ispring.startservicedemo;
Import Android.app.Service;
Import android.content.Intent;
Import Android.os.Binder;
Import Android.os.IBinder;
Import Android.util.Log;
Import Java.util.Random;
public class Testservice extends Service {public class Mybinder extends binder{public testservice GetService () {
return testservice.this;
The communication between the caller client and service is implemented through binder private Mybinder binder = new Mybinder ();
Private final Random generator = new Random (); @Override public void OnCreate () {log.i ("Demolog", "Testservice-> onCreate, Thread:" + thread.currentthread (). g
Etname ());
Super.oncreate (); @Override public int Onstartcommand (Intent Intent, int flags, int startid) {log.i ("Demolog", "Testservice" ;
Onstartcommand, Startid: "+ Startid +", Thread: "+ thread.currentthread (). GetName ());
return start_not_sticky; @Override public IBinder onbind (Intent Intent) {log.i ("Demolog", "Testservice->Onbind, Thread: "+ thread.currentthread (). GetName ());
return binder; @Override public boolean onunbind (Intent Intent) {log.i ("Demolog", "Testservice-> Onunbind, from:" + inten
T.getstringextra ("from"));
return false; @Override public void OnDestroy () {log.i ("Demolog", "Testservice-> OnDestroy, Thread:" + thread.currentth
Read (). GetName ());
Super.ondestroy ();
//getrandomnumber is a service that exposes public methods that are called by the client to be publicly available int getrandomnumber () {return generator.nextint ();
}
}
In this app, in addition to Testservice, there are two Activity:activitya and Activityb, both of which are callers to the service, that is, the client in the Client-server interface.
Activitya is the app's startup interface, and the interface is as follows:
The code for Activitya is as follows:
Package Com.ispring.startservicedemo;
Import android.app.Activity;
Import Android.content.ComponentName;
Import android.content.Intent;
Import android.content.ServiceConnection;
Import Android.os.Bundle;
Import Android.os.IBinder;
Import Android.util.Log;
Import Android.view.View;
Import Android.widget.Button;
public class Activitya extends activity implements Button.onclicklistener {private testservice service = NULL;
Private Boolean isbound = false; Private Serviceconnection conn = new Serviceconnection () {@Override public void onserviceconnected (componentname
Name, IBinder binder) {isbound = true;
Testservice.mybinder Mybinder = (testservice.mybinder) binder;
Service = Mybinder.getservice ();
LOG.I ("Demolog", "Activitya onserviceconnected");
int num = Service.getrandomnumber ();
LOG.I ("Demolog", "Activitya testservice GetRandomNumber method, Result:" + num); @Override public void onservicedisconnected (componentnameName) {Isbound = false;
LOG.I ("Demolog", "Activitya onservicedisconnected");
}
};
@Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_a);
LOG.I ("Demolog", "Activitya-> onCreate, Thread:" + thread.currentthread (). GetName ());
@Override public void OnClick (View v) {if (V.getid () = R.id.btnbindservice) {//Click the Bindservice button
Intent Intent = new Intent (this, testservice.class);
Intent.putextra ("from", "Activitya");
LOG.I ("Demolog", "----------------------------------------------------------------------");
LOG.I ("Demolog", "Activitya execution Bindservice");
Bindservice (Intent, Conn, bind_auto_create); }else if (v.getid () = = R.id.btnunbindservice) {//click the "Unbindservice" button if (isbound) {log.i ("Demolog", "-
--------------------------------------------------------------------"); LOG.I ("Demolog", "Activitya Executive Unbindservice ");
Unbindservice (conn); }else if (v.getid () = = R.id.btnstartactivityb) {//Click the ' Start Activityb ' button Intent Intent = new Intent (This,
Activityb.class);
LOG.I ("Demolog", "----------------------------------------------------------------------");
LOG.I ("Demolog", "Activitya start Activityb");
StartActivity (Intent); }else if (v.getid () = = R.id.btnfinish) {//Click Finish button log.i ("Demolog", "-------------------------------------
---------------------------------");
LOG.I ("Demolog", "Activitya execution Finish");
This.finish ();
}} @Override protected void OnDestroy () {Super.ondestroy ();
LOG.I ("Demolog", "Activitya-> OnDestroy");
}
}
You can start the Activityb,activityb interface as follows by clicking Start Activityb on the Activitya:
The code for ACTIVITYB is as follows:
Package Com.ispring.startservicedemo;
Import android.app.Activity;
Import Android.content.ComponentName;
Import android.content.Intent;
Import android.content.ServiceConnection;
Import Android.os.Bundle;
Import Android.os.IBinder;
Import Android.util.Log;
Import Android.view.View;
Import Android.widget.Button;
public class Activityb extends activity implements Button.onclicklistener {private testservice service = NULL;
Private Boolean isbound = false; Private Serviceconnection conn = new Serviceconnection () {@Override public void onserviceconnected (componentname
Name, IBinder binder) {isbound = true;
Testservice.mybinder Mybinder = (testservice.mybinder) binder;
Service = Mybinder.getservice ();
LOG.I ("Demolog", "Activityb onserviceconnected");
int num = Service.getrandomnumber ();
LOG.I ("Demolog", "Activityb testservice GetRandomNumber method, Result:" + num); @Override public void onservicedisconnected (componentnameName) {Isbound = false;
LOG.I ("Demolog", "Activityb onservicedisconnected");
}
};
@Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_b); @Override public void OnClick (View v) {if (V.getid () = R.id.btnbindservice) {Intent Intent = new Intent (
this, testservice.class);
Intent.putextra ("from", "activityb");
LOG.I ("Demolog", "----------------------------------------------------------------------");
LOG.I ("Demolog", "Activityb execution Bindservice");
Bindservice (Intent, Conn, bind_auto_create); }else if (v.getid () = = R.id.btnunbindservice) {if (isbound) {log.i ("Demolog", "-------------------------------
---------------------------------------");
LOG.I ("Demolog", "Activityb execution Unbindservice");
Unbindservice (conn); }else if (v.getid () = = R.id.btnfinish) {//Click Finish button log.i ("Demolog", "----------------------------------------------------------------------");
LOG.I ("Demolog", "Activityb execution Finish");
This.finish ();
@Override public void OnDestroy () {Super.ondestroy ();
LOG.I ("Demolog", "Activityb-> OnDestroy");
}
}
We do not click on the above button for the moment, first look at the Testservice and Activitya code.
The service and the caller must be prepared to interact with the service, the caller (client-side).
Let's look at the work the service needs to do first.
The key to using Bindservice to connect the client to the server is binder, in Testservice, where we write an inner class mybinder, which has a public method GetService, By this method we can obtain the testservice containing Mybinder. If you want your service to support the Bindservice startup method, you must return an instance of the IBinder type in the service's onbind. In the example, we instantiate a Mybinder instance binder as a testservice field and use it as the Onbind return value.
Let's conclude that if you want the service to support Bindservice invocation, the service needs to do the following things:
1. Returns an instance of the IBinder type in the Onbind method of the service.
2. The IBinder instance returned by the Onbind method needs to be able to return the service instance itself or expose the service public method through binder. In general, the easiest way to do this is to get binder into the inner class of the service, and then add a GetService-like method to the binder to return the service that contains the binder. So that the client can get the service instance through this method.
We already know what the service needs to do, so let's take a look at the work the caller needs to do.
In our example, the caller (that is, the client side) is Activitya, in which we initialize an instance of the Serviceconnection type. You need to override its Onserviceconnected method and onservicedisconnected method. We need to pass this instance of the Serviceconnection type as a parameter to the Bindservice method, and when the service has not yet been created, Android creates an instance of the service and then executes the service's Onbind method, An instance of the IBinder type is obtained, and the method is passed as a parameter into the Serviceconnection onserviceconnected method of the client end. The execution of the Onserviceconnected method indicates that the client side can obtain an instance of the service's IBinder type and then convert IBinder to its own actual binder type. It can then be obtained directly from the instance of the service or by binder the public method directly, depending on the specific implementation of the binder in the service. In this example, in the Onserviceconnected method, the caller Activitya the corresponding service through the binder GetService method, We can then invoke the service's public methods directly to achieve the purpose of using the service, so that the client and service establish a connection through ibinder to interact. The Onservicedisconnected method is triggered when the client loses connection with the service.
Let's summarize what the client side is going to do:
1. Create an instance of the Serviceconnection type and override its Onserviceconnected method and onservicedisconnected method.
2. When Android executes the onserviceconnected callback method, we can obtain the client's connection to the service by IBinder instance to the service instance object or by directly calling Binder's public method.
3. When Android executes the onservicedisconnected callback method, which means that the client and service disconnect, we are here to write some of the processing that needs to be done after disconnecting.
After knowing how to have the client interact with the service, we run our app, watch the execution of each callback method, and we have three test processes.
Test Flow A
The test involves Activitya, but does not involve activityb.
First we click on the "Bindservice" button in Activitya, and then click on the "Unbindservice" button, the output is as follows:
First, we can see from the above code that the callback methods executed in the service are executed in the main thread.
When we call the Bindservice method, we need to pass an instance of intent, serviceconnection, and so on, and intent contains the service,serviceconnection we're going to bind, as we mentioned above, Its onserviceconnected method and onservicedisconnected method are realized. After calling Bindservice, since the service does not exist at this time, Android will first create an Testservice instance and execute its OnCreate callback method, OnCreate the method will only be invoked once in its lifecycle. The service's Onbind method is then invoked, which executes only after the first Bindservice call, and Onbind returns an instance of the IBinder type after execution, at which point Android saves the IBinder instance. This IBinder instance is shared with all the client. The next time the other client executes Bindservice, the Onbind method will not be executed, because we have already obtained a IBinder instance, and Android will use the IBinder instance directly. After getting the IBinder instance, Android executes the onserviceconnected method in the client-side serviceconnection, where we get the IBinder instance, The Testservice instance is obtained through the IBinder instance, so that our client Activitya connects with Testservice through IBinder, we can invoke the Testservice public method, For example, call its GetRandomNumber method to get random numbers.
Summarize what happens after calling Bindservice:
Client Execution Bindservice->
If service does not exist, service executes OnCreate->
If Onbind,service execution Onbind is not performed->
Instance of client Serviceconnection execution onserviceconnected
After executing the bindservice, a total of one client is connected to the Testservice, that is, Activitya, and the client is unbound from the service each time the client invokes the Unbindservice method. After unbinding from a client, the service detects if another client is bound to its connection, and if no other client is connected, the service executes the Onunbind method and then executes the OnDestroy method, eventually destroy themselves. When Activitya executes the Unbindservice, the only client and Testservice unbind the relationship, Testservice executes the Onunbind method, and then executes the OnDestroy method.
Summarize what happens after calling Unbindservice:
Client Execution Unbindservice->
Client and Service Unbound connection state->
Service detects if there are other client connections and if there is no->
Service Execution Onunbind->
Service Execution OnDestroy
Test Flow B
After testing the first process, we turned off the app, restarted the app, and conducted the second Test process.
The test also involved Activitya only, not involving Activityb. First click on the "Bindservice" button in the Activitya, then click the "Finish" button, the output is as shown in the following image:
In this test, we first click on the "Bindservice" button, so that Activitya bound Testservice, but we did not call Unbindservice, but directly by calling the "Finish" button to let the Activitya directly destroy , through the above output, we can see that when the Activitya is destroyed, the Activitya OnDestroy callback method is executed, and then the Onunbind, OnDestroy callback method is executed testservice sequentially. Testservice destroyed. After the client and service are connected by Bindservice, if the client destroys, the client automatically binds to the service, which is equivalent to executing unbindservice before destroy, After the Activitya is destroyed, the Activitya and service are unbound, and no client and service are connected to the binding state, so the service executes the Onunbind callback method, indicating that no client has played with me, Finally, the OnDestroy callback method is executed.
Test process C
We have only involved Activtitya in the previous two test processes, and this test process involves both Activitya and activityb.
First turn off the app, restart the app, and test by following these steps:
1. Click the "Bindservice" button in Activitya
2. Click the "Start Activityb" button in Activitya to switch the interface to ACTIVITYB
3. Click the "Bindservice" button in Activityb
4. Click the "Unbindservice" button in Activityb
5. Click the "Finish" button in Activityb
6. Click the "Unbindservice" button in Activitya
Logcat output results are as follows:
Here we analyze the impact of each step in turn to fully understand the lifecycle of the service initiated through Bindservice:
Click the "Bindservice" button in Activitya
because the Testservice instance does not exist in the initial case, the Testservice is not running. The first call to Bindservice instantiates Testservice, then executes its Onbind method, and gets an instance of the IBinder type. It is then passed as a parameter into the Activitya serviceconnection onserviceconnected method, signifying that Activitya has established a binding connection with Testservice, At this point only Activitya client-side is bound to testservice.
Click the "Start Activityb" button in Activitya to switch the interface to ACTIVITYB
Click the "Bindservice" button in Activityb
because Testservice is already running, the Testservice instance is not recreated when Activityb calls Bindservice, so the Testservice callback method is not executed. Because the Testservice Onbind callback method was executed while the Activitya was executing Bindservice, the IBinder instance was obtained, and the IBinder instance was shared among all the client. So when Activityb executes Bindservice, it does not execute its Onbind callback method, but rather gets the IBinder instance that was last acquired. As the parameter is passed into the Activityb serviceconnection onserviceconnected method, it indicates that ACTIVITYB has established a binding connection with Testservice, At this point, there are two client single client (Activitya and Activityb) bound to Testservice.
Click the "Unbindservice" button in Activityb
after Activityb executes the unbindservice, Activityb is unbound from Testservice. Testservice executes the Onunbind method, OnDestroy method, when no client and service are in a bound connection state. However, since there are activitya this client and Testservice are in a bound connection, the service's Onbind and OnDestroy callback methods are not executed.
Click the "Finish" button in Activityb
after performing the Activityb finish method, the Activityb is destroyed and the interface is returned to Activitya
Click the "Unbindservice" button in Activitya
After Activitya executes Unbindservice, Activitya and Testservice are unbound so that no client-side clients are connected to the Testservice, and Android destroys Testservice. The Testservice Onunbind method is executed before it is destroyed before the OnDestroy method is executed, so that Testservice is destroyed.
Bindservice Life cycle Flowchart
Specifically, the client referred to in this article refers to the component component, such as an activity. If multiple calls to the Bindservice method connect the service in an activity, the activity is only a client, not multiple client, for service.
Finally, we summarize the lifecycle of Bindservice-initiated service to the following flowchart:
I hope this article will help you understand the use of bindservice.