Android TV development tutorial

  the whole content of Service will be covered in this article. We will analyze it around the following main knowledge points:

  • Service brief overview
  • Declaration of Service in manifest file
  • Service startup service implementation method and its detailed explanation
  • Three implementation methods of Service binding Service
  • On the conversion between startup service and binding service
  • Front desk service and notification sending
  • The difference between Service and Thread
  • Key points of managing the service life cycle
  • Implicit startup problems and solutions above Android 5.0
  • Implementation idea of ensuring that services are not killed

1. Brief overview of service

  Service is an application component that can perform long-running operations in the background without user interface. The Service can be started by other application components (such as Activity). Once the Service is started, it will always run in the background. Even if the component (Activity) that starts the Service has been destroyed, it will not be affected. In addition, components can be bound to services to interact with them, or even perform interprocess communication (IPC). For example, services can handle network transactions, play music, execute file I/O or interact with content providers, all of which can be carried out in the background. Services are basically divided into two forms:

  • Start state

   when an application component (such as an Activity) starts a service by calling startService(), the service is in the "start" state. Once started, the service can run indefinitely in the background. Even if the component that started the service has been destroyed, it will not be affected. The service can be stopped unless it is called manually. The started service usually performs a single operation and will not return the result to the caller.

  • Binding status

  when the application component binds to the service by calling bindService(), the service is in the "binding" state. Binding service provides a client server interface, which allows components to interact with services, send requests, obtain results, and even use interprocess communication (IPC) to perform these operations across processes. The binding service runs only when it is bound to another application component. Multiple components can be bound to the service at the same time, but the service will be destroyed after all the components are unbound.

2. Statement of service in the list file

The specific startup status is divided into two types: androidservice (and Service), which are inherited by the base state XML, so before analyzing these two states, let's take a look at the Service in AndroidManifest.xml The declaration syntax in XML has the following format:

   
  1. <service android:enabled=[ "true" | "false"]
  2. android:exported=[ "true" | "false"]
  3. android:icon= "drawable resource"
  4. android:isolatedProcess=[ "true" | "false"]
  5. android:label= "string resource"
  6. android:name= "string"
  7. android:permission= "string"
  8. android:process= "string" >
  9. . . .
  10. </service>
  • android:exported: indicates whether it can be implicitly called by other applications. Its default value is determined by whether there is an intent filter in the service. If there is an intent filter, the default value is true, otherwise it is false. If it is false, even if there is an intent filter match, it cannot be opened, that is, it cannot be implicitly called by other applications.

  • android:name: corresponding Service class name

  • android:permission: permission statement

  • android:process: whether it needs to run in a separate process. When it is set to android:process = ": remote", it represents that the Service runs in a separate process. Note that ":" is very important. It means to append the current package name before the current process name, so "remote" and ": remote" do not have the same meaning. The process name of the former is: remote, and the process name of the latter is: app packagename: remote.

  • android:isolatedProcess: setting true means that the service will run under a special process, which is separated from other processes in the system and does not have its own permissions. The only way to communicate with it is through the API of the service (bind and start).

  • android:enabled: whether it can be instantiated by the system. The default is true. Because the parent tag also has the enable attribute, the service can be activated only when both are true by default, otherwise it will not be activated.  
       ok ~, let's first understand these statements about the Service in the manifest file, and then analyze the Service startup Service and binding Service in detail

3.Service startup service

  to create a Service first, you must create a subclass of Service (or use one of its existing subclasses, such as IntentService). In the implementation, we need to rewrite some callback methods to process the Service life cycle For some key processes, let's analyze which callback methods need to be rewritten through a simple case?

   
  1. package com.zejian.ipctest.service;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. import android.support.annotation.Nullable;
  6. /**
  7. * Created by zejian
  8. * Time 2016/9/29.
  9. * Description:service simple demo
  10. */
  11. public class SimpleService extends Service {
  12. /**
  13. * Called only when the service is bound
  14. * Methods that must be implemented
  15. * @param intent
  16. * @return
  17. */
  18. @Nullable
  19. @Override
  20. public IBinder onBind (Intent intent) {
  21. return null;
  22. }
  23. /**
  24. * When the service is created for the first time, the system will call this method to execute the one-time setup program (before calling onStartCommand() or onBind()).
  25. * If the service is already running, this method will not be called. This method is called only once
  26. */
  27. @Override
  28. public void onCreate () {
  29. System.out.println( "onCreate invoke");
  30. super.onCreate();
  31. }
  32. /**
  33. * It will be called back every time the Service is started through the startService() method.
  34. * @param intent
  35. * @param flags
  36. * @param startId
  37. * @return
  38. */
  39. @Override
  40. public int onStartCommand (Intent intent, int flags, int startId) {
  41. System.out.println( "onStartCommand invoke");
  42. return super.onStartCommand(intent, flags, startId);
  43. }
  44. /**
  45. * Callback during service destruction
  46. */
  47. @Override
  48. public void onDestroy () {
  49. System.out.println( "onDestroy invoke");
  50. super.onDestroy();
  51. }
  52. }

   from the above code, we can see that SimpleService inherits the Service class and rewrites the onBind method. This method must be rewritten. However, since it is a Service in startup state at this time, this method does not need to be implemented and can return null. It is only necessary to implement this method and return an IBinder implementation class (which will be described in detail later), and then rewrites onCreate, onStartCommand onDestroy has three main life cycle methods, which are described as follows:

  • onBind()

  the system will call this method when another component wants to bind to a service (such as executing RPC) by calling bindService(). In the implementation of this method, an implementation class of IBinder interface must be returned for the client to communicate with the service. This method must be overridden whether it is in the startup state or binding state, but it returns null directly in the startup state.

  • onCreate()

   when the service is created for the first time, the system will call this method to execute the one-time setting program (before calling onStartCommand() or onBind()). If the service is already running, this method will not be called, it will only be called once

  • onStartCommand()

   the system will call this method when another component (such as Activity) requests to start the service by calling startService(). Once this method is executed, the service starts and can run indefinitely in the background. If you implement this method yourself, you need to stop the service by calling stopSelf() or stopService() after the service work is completed. (in the binding state, this method does not need to be implemented.)

  • onDestroy()

  the system will call this method when the service is no longer used and will be destroyed. The service should implement this method to clean up all resources, such as threads, registered listeners, receivers, etc. This is the last call received by the service.

   let's test the calling sequence of Service startup status methods through Demo. The MainActivity code is as follows:

   
  1. package com.zejian.ipctest;
  2. import android.content.Intent;
  3. import android.os.Bundle;
  4. import android.support.v7.app.AppCompatActivity;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import com.zejian.ipctest.service.SimpleService;
  8. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  9. private Button startBtn;
  10. private Button stopBtn;
  11. @Override
  12. protected void onCreate (Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.activity_main);
  15. startBtn= (Button) findViewById(R.id.startService);
  16. stopBtn= (Button) findViewById(R.id.stopService);
  17. startBtn.setOnClickListener( this);
  18. assert stopBtn != null;
  19. stopBtn.setOnClickListener( this);
  20. }
  21. @Override
  22. public void onClick (View v) {
  23. Intent it= new Intent( this, SimpleService.class);
  24. switch (v.getId()){
  25. case R.id.startService:
  26. startService(it);
  27. break;
  28. case R.id.stopService:
  29. stopService(it);
  30. break;
  31. }
  32. }
  33. }

Remember to declare service in the manifest configuration file (the declaration method is similar to that of Activity):

   
  1. <manifest ... >
  2. ...
  3. <application ... >
  4. <service android:name=".service.SimpleService" />
  5. ...
  6. </application>
  7. </manifest>

   from the code, you can start the service by using the startService(Intent intent) method. You only need to pass an Intent object, and specify the service to be started in the Intent object. The service started with the startService() method must be stopped with the stopService() method outside the service, and the stopSelf() method can be called inside the service to stop the current service. If you use the startService() or stopSelf() method to request to stop the service, the system will destroy the service as soon as possible. Once the service is started, the component will be destroyed without any attention. Once the service is started, the component will not work until it is in the state of being associated with the service. Once the service is started, it will be destroyed without any attention, Finally, call the stopService method. Base note: The Log screenshot is as follows:

   it can be seen from the Log that when the startService method is called for the first time, onCreate method and onStartCommand method will be called successively, while when the startService method is called for many times, only onStartCommand method will be called. Finally, when we call stopService method to stop the Service, onDestory method will be called back, which is the execution cycle of the Service in the start state. Then we go back and further analyze onStartCommand (intent, int flags, int startid). This method has three incoming parameters, and their meanings are as follows:

onStartCommand(Intent intent, int flags, int startId)

  • Intent: when starting, the intent passed by the starting component, such as Activity, can use intent to encapsulate the required parameters and pass them to the Service

  • flags: indicates whether there is additional data when starting the request. The optional values are 0 and START_FLAG_REDELIVERY,START_FLAG_RETRY, 0 means no, and their specific meanings are as follows:

    • START_FLAG_REDELIVERY 
      This value represents the return value of onStartCommand method
      START_REDELIVER_INTENT, and it will call the stopSelf method to stop the Service before the last Service is killed. Including START_REDELIVER_INTENT means that when the Service is killed by the system due to insufficient memory, it will rebuild the Service and call onStartCommand() through the last intent passed to the Service. At this time, the intent has a value.

    • START_FLAG_RETRY 
      This flag means that when there is no return value after onStartCommand is called, it will try to call onStartCommand() again.

  • startId: indicates the unique ID of the current service. Used in combination with stopSelfResult (int startId), stopSelfResult can more safely stop the service according to the ID.

   in fact, the return value int type of onStartCommand is the most noteworthy. It has three optional values, START_STICKY, START_NOT_STICKY,START_REDELIVER_INTENT, their specific meanings are as follows:

  • START_STICKY 
       when the Service is kill ed by the system due to insufficient memory and the memory is free again after a period of time, the system will try to re create the Service. Once the Service is created successfully, the onStartCommand method will be called back, but the Intent in it will be null, unless there is a suspended Intent, such as pending. This state is more suitable for media players or similar services that do not execute commands but run indefinitely and wait for jobs.

  • START_NOT_STICKY 
       after the Service is kill ed by the system due to insufficient memory, the system will not try to re create the Service even if the system memory is free again. Unless the program calls startService again to start this Service, this is the safest option to avoid running the Service when it is unnecessary and when the application can easily restart all unfinished jobs.

  • START_REDELIVER_INTENT 
       when the Service is kill ed by the system due to insufficient memory, it will rebuild the Service and call onStartCommand() through the last Intent passed to the Service. Any pending Intent will be passed in turn. And START_STICKY is different in that the passed Intent will be non empty, which is the Intent in the last call to startService. This value applies to services that actively execute jobs that should be restored immediately, such as downloading files.

   since the onStartCommand method will be called every time the Service is started (calling startService), we can use Intent to pass the required parameters to the Service through this method, then process the events in the onStartCommand method, and finally select different Flag return values according to the needs to achieve more friendly control of the program. OK ~, the above is the analysis of the Service in the startup state. Then let's see how the Service in the binding state is handled?

4.Service binding service

   binding Service is another variant of Service. When the Service is in the binding state, it represents the server in the client server interface. When other components (such as Activity) are bound to the Service (sometimes we may need to call the method in the Service from the Activity component. At this time, after the Activity is attached to the Service in the way of binding, we can easily connect the method to the specified method in the Service), components (such as Activity) can send requests to the Service (that is, the server) or call the method of the Service (the server), At this time, the bound Service (server) will receive information and respond, and can even perform inter process communication through the bound Service (i.e. IPC, which will be analyzed separately later). Different from starting the Service, the life cycle of the binding Service is usually only active when serving other application components (such as Activity) and will not run in the background indefinitely, that is, after the host (such as Activity) unbinds, the binding Service will be destroyed. So how to implement binding services? In fact, we must provide an implementation class of IBinder interface, which is used to provide the programming interface used by the client to interact with the Service. The interface can define the interface through three methods:

  • Extend Binder class
       if the Service is dedicated to its own application, and the Service (server) runs in the same process as the client (common situation), the interface should be created by extending the Binder class and returning an instance of it from onBind(). After receiving Binder, the client can use it to directly access the public methods available in Binder implementation and Service. If our Service is only the background working thread of our own application, this method is preferred. The only reason why the interface is not created in this way is that the Service is called by other applications or different processes.

  • Using Messenger
       messenger can be translated into messenger. Through it, Message objects can be delivered in different processes (the Messager in the Handler, so the Handler is the basis of messenger). The data we need to deliver can be stored in the Message and then delivered between processes. If you need to make the interface work across different processes, you can use messenger to create an interface for the service, and the client can use the Message object to send commands to the service. At the same time, the client can also define its own messenger so that the service can return messages. This is the simplest way to implement interprocess communication (IPC), because messenger will create a queue containing all requests in a single thread, that is, Messenger processes messages sent by the client in a serial way, so we don't have to thread safety design the service.

  • Use AIDL
       because messenger processes the messages sent by the client in a serial way, if a large number of messages are sent to the Service at the same time, the Service can still process them one by one, which is the disadvantage of messenger cross process communication. Therefore, if there are a large number of concurrent requests, Messenger will be unable to meet its needs, and aidl (android interface definition language) will come in handy, But in fact, the underlying implementation of messenger's cross process approach is aidl, but android system helps us package it into transparent messenger. Therefore, if we want the Service to handle multiple requests at the same time, we should use aidl. In this case, the Service must have multi-threaded processing capability and adopt thread safe design. To use aidl, you must create a to define the programming interface aidl file. The Android SDK tool uses this file to generate an abstract class that implements the interface and handles IPC, which can then be extended within the Service.

   we can freely choose the above three implementation methods according to our needs, but it should be noted that most applications "will not" use AIDL to create binding services, because it may require multi-threaded processing capability and may increase the complexity of implementation. Therefore, AIDL is not suitable for most applications. This article does not intend to explain how to use AIDL (another article will be opened later to analyze AIDL). Next, we will analyze the use of extended Binder class and Messenger respectively.

4.1 extend Binder class

   as described above, if our service is only used by local applications and does not need to work across processes, we can implement our own Binder class to allow clients to directly access the public methods in the service through this class. Its use and development steps are as follows

  • 1. Create the BindService server, inherit from the Service, create an instance object that implements the IBinder interface in the class, and provide public methods for the client to call
  • 2. Return this Binder instance from the onBind() callback method.
  • 3. In the client, receive the Binder from the onServiceConnected() callback method and call the binding service using the provided method.

   note: this method is only effective when the client and service are in the same application and process. For example, this method is very effective for music applications that need to bind the Activity to their own services that play music in the background. Another reason why the service and client must be in the same application is to facilitate the client to convert the returned object and call its API correctly. The service and client must also be in the same process, because this method does not perform any cross process marshalling.  
   the following is an example of extending Binder class. Let's take a look at the implementation of bindservice on the Service side java

   
  1. package com.zejian.ipctest.service;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.Binder;
  5. import android.os.IBinder;
  6. import android.support.annotation.Nullable;
  7. import android.util.Log;
  8. /**
  9. * Created by zejian
  10. * Time 2016/10/2.
  11. * Description:Binding service simple instance -- server
  12. */
  13. public class LocalService extends Service{
  14. private final static String TAG = "wzj";
  15. private int count;
  16. private boolean quit;
  17. private Thread thread;
  18. private LocalBinder binder = new LocalBinder();
  19. /**
  20. * Create a Binder object and return it to the client, that is, the Activity, which provides an interface for data exchange
  21. */
  22. public class LocalBinder extends Binder {
  23. // Declare a method, getService. (provided for client call)
  24. LocalService getService () {
  25. // Return the current object LocalService, so that we can call the public method of Service on the client side
  26. return LocalService. this;
  27. }
  28. }
  29. /**
  30. * Return the Binder class to the client
  31. */
  32. @Nullable
  33. @Override
  34. public IBinder onBind (Intent intent) {
  35. return binder;
  36. }
  37. @Override
  38. public void onCreate () {
  39. super.onCreate();
  40. Log.i(TAG, "Service is invoke Created");
  41. thread = new Thread( new Runnable() {
  42. @Override
  43. public void run () {
  44. // count is incremented by 1 every second until quit is true.
  45. while (!quit) {
  46. try {
  47. Thread.sleep( 1000);
  48. } catch (InterruptedException e) {
  49. e.printStackTrace();
  50. }
  51. count++;
  52. }
  53. }
  54. });
  55. thread.start();
  56. }
  57. /**
  58. * Public method
  59. * @return
  60. */
  61. public int getCount (){
  62. return count;
  63. }
  64. /**
  65. * Called when unbound
  66. * @return
  67. */
  68. @Override
  69. public boolean onUnbind (Intent intent) {
  70. Log.i(TAG, "Service is invoke onUnbind");
  71. return super.onUnbind(intent);
  72. }
  73. @Override
  74. public void onDestroy () {
  75. Log.i(TAG, "Service is invoke Destroyed");
  76. this.quit = true;
  77. super.onDestroy();
  78. }
  79. }

   BindService class inherits from Service. In this class, a LocalBinder is created, which inherits from binder class. LocalBinder declares a getService method. The client can access this method to obtain the instance of LocalService object. As long as the client obtains the instance of LocalService object, it can call the public method of LocalService server, such as getCount method. It is worth noting that we return the binder object in onBind method, This object is the specific instance of LocalBinder, and the binder object will eventually be returned to the client. The client can interact with the server through the returned binder object. Next, let's look at the implementation of BindActivity on the client:

   
  1. package com.zejian.ipctest.service;
  2. import android.app.Activity;
  3. import android.app.Service;
  4. import android.content.ComponentName;
  5. import android.content.Intent;
  6. import android.content.ServiceConnection;
  7. import android.os.Bundle;
  8. import android.os.IBinder;
  9. import android.util.Log;
  10. import android.view.View;
  11. import android.widget.Button;
  12. import com.zejian.ipctest.R;
  13. /**
  14. * Created by zejian
  15. * Time 2016/10/2.
  16. * Description:Binding service instance -- client
  17. */
  18. public class BindActivity extends Activity {
  19. protected static final String TAG = "wzj";
  20. Button btnBind;
  21. Button btnUnBind;
  22. Button btnGetDatas;
  23. /**
  24. * ServiceConnection Represents the connection to the service. It has only two methods,
  25. * onServiceConnected And onservice disconnected,
  26. * The former is called when the operator successfully connects to a service, while the latter is called when the connection is interrupted due to service crash or killing
  27. */
  28. private ServiceConnection conn;
  29. private LocalService mService;
  30. @Override
  31. protected void onCreate (Bundle savedInstanceState) {
  32. super.onCreate(savedInstanceState);
  33. setContentView(R.layout.activity_bind);
  34. btnBind = (Button) findViewById(R.id.BindService);
  35. btnUnBind = (Button) findViewById(R.id.unBindService);
  36. btnGetDatas = (Button) findViewById(R.id.getServiceDatas);
  37. //Create binding object
  38. final Intent intent = new Intent( this, LocalService.class);
  39. // Open binding
  40. btnBind.setOnClickListener( new View.OnClickListener() {
  41. @Override
  42. public void onClick (View v) {
  43. Log.d(TAG, "Binding call: bindService");
  44. //Call binding method
  45. bindService(intent, conn, Service.BIND_AUTO_CREATE);
  46. }
  47. });
  48. // Unbind
  49. btnUnBind.setOnClickListener( new View.OnClickListener() {
  50. @Override
  51. public void onClick (View v) {
  52. Log.d(TAG, "Unbind call: unbindService");
  53. // Unbind
  54. if(mService!= null) {
  55. mService = null;
  56. unbindService(conn);
  57. }
  58. }
  59. });
  60. // get data
  61. btnGetDatas.setOnClickListener( new View.OnClickListener() {
  62. @Override
  63. public void onClick (View v) {
  64. if (mService != null) {
  65. // Get the data exposed by the Service by binding the Binder object passed by the Service
  66. Log.d(TAG, "Obtain data from the server:" + mService.getCount());
  67. } else {
  68. Log.d(TAG, "It's not bound yet. Bind first,Unable to get data from the server");
  69. }
  70. }
  71. });
  72. conn = new ServiceConnection() {
  73. /**
  74. * The interface method interacting with the server is called back when binding the Service. This method obtains the IBinder object passed by the binding Service,
  75. * Through this IBinder object, the interaction between host and Service can be realized.
  76. */
  77. @Override
  78. public void onServiceConnected (ComponentName name, IBinder service) {
  79. Log.d(TAG, "Bind successfully called: onServiceConnected");
  80. // Get Binder
  81. LocalService. LocalBinder binder = (LocalService.LocalBinder) service;
  82. mService = binder.getService();
  83. }
  84. /**
  85. * Called back when unbinding. But it is not called under normal circumstances. Its calling time is when the Service service is accidentally destroyed,
  86. * For example, this method is called automatically when the memory resources are insufficient.
  87. */
  88. @Override
  89. public void onServiceDisconnected (ComponentName name) {
  90. mService= null;
  91. }
  92. };
  93. }
  94. }

  in the client, we created a ServiceConnection object, which represents the connection with the service. It has only two methods, onServiceConnected and onServiceDisconnected. Its meaning is as follows:

  • onServiceConnected(ComponentName name, IBinder service) 
    The system will call this method to pass the IBinder returned by the onBind() method of the service. Service is the IBinder implementation class object returned by the server. Through this object, we can call to obtain the LocalService instance object, and then call the public method of the server. ComponentName is a class that encapsulates the information of components (Activity, Service, BroadcastReceiver, or ContentProvider), such as package name, component description and other information. This parameter is rarely used.

  • onServiceDisconnected(ComponentName name) 
    The Android system will call this method when the connection with the service is unexpectedly interrupted (for example, when the service crashes or is terminated). Note: when the client unbinds, the system "will never" call this method.

   
  1. conn = new ServiceConnection() {
  2. @Override
  3. public void onServiceConnected (ComponentName name, IBinder service) {
  4. Log.d(TAG, "Bind successfully called: onServiceConnected");
  5. // Get Binder
  6. LocalService. LocalBinder binder = (LocalService.LocalBinder) service;
  7. mService = binder.getService();
  8. }
  9. @Override
  10. public void onServiceDisconnected (ComponentName name) {
  11. mService= null;
  12. }
  13. };

   before onServiceConnected() is called back, we also need to bind the current Activity to the service LocalService. The binding service is through the bindService() method, and the unbindService() method is used to unbind the service. The two methods are resolved as follows:

  • bindService(Intent service, ServiceConnection conn, int flags) 
    This method performs the binding Service operation, in which Intent is the intention of the Service we want to bind (that is, LocalService), and ServiceConnection represents the connection with the Service. It has only two methods. As analyzed earlier, flags specifies whether to automatically create the Service during binding. 0 means not to create and bind automatically_ AUTO_ Create stands for automatic creation.

  • unbindService(ServiceConnection conn) 
    This method performs the operation of unbinding. ServiceConnection represents the connection with the service. It has only two methods, which have been analyzed earlier.

After the Activity is bound to the LocalService through bindService(), ServiceConnection#onServiceConnected() will be called back and the LocalService instance object mService can be obtained. Then we can call the public method of the LocalService server. Finally, we need to declare the Service in the manifest file. The client layout file is implemented as follows:

   
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation= "vertical" android:layout_width= "match_parent"
  4. android:layout_height= "match_parent">
  5. <Button
  6. android:id= "@+id/BindService"
  7. android:layout_width= "wrap_content"
  8. android:layout_height= "wrap_content"
  9. android:text= "Binding server"
  10. />
  11. <Button
  12. android:id= "@+id/unBindService"
  13. android:layout_width= "wrap_content"
  14. android:layout_height= "wrap_content"
  15. android:text= "Unbind"
  16. />
  17. <Button
  18. android:id= "@+id/getServiceDatas"
  19. android:layout_width= "wrap_content"
  20. android:layout_height= "wrap_content"
  21. android:text= "Obtain service party data"
  22. />
  23. </LinearLayout>

Base note: we run the program, click the binding service and click the binding service several times, then call the getCount() in LocalService for data, and then call the unbound method to remove the service. The results are as follows:

   it can be seen from the Log that when we click bind Service for the first time, the onCreate() and onBind methods of the LocalService server will be called successively. At this time, the ServiceConnection#onServiceConnected() of the client is called and returns the LocalBinder object, and then the LocalBinder#getService method is called to return the LocalService instance object. At this time, the client holds the instance object of the LocalService, You can also call the declared public methods in the LocalService class at will. What is more noteworthy is that we call the bindService method many times to bind the LocalService server, while the onBind method of the LocalService is called only once, that is, the onBind method will be called back when the bindService is called for the first time. Then we click to get the data of the server. From the Log, we can see that we click three times and get three different data of the server through getCount(). Finally, click unbind. At this time, the onUnBind and onDestroy methods of LocalService are called back in turn, and only one unbinding is required for multiple bindings. This scenario also shows that the Service life cycle method calls in the binding state are onCreate(), onBind, onUnBind and onDestroy in turn. ok ~, the above is the binding callback method between the client and the server in the same process of the same application.

4.2 using Messenger

   after understanding how to use the communication of the same process in IBinder application, we will then understand the communication between service and remote process (i.e. between different processes). The simplest way of communication between different processes is to use Messenger service to provide communication interface. In this way, we can perform interprocess communication (IPC) without using AIDL. Here are the main steps for using Messenger:

  • 1. The service implements a Handler, which receives the callback of each call from the client

  • 2.Handler is used to create Messenger object (reference to handler)

  • 3.Messenger creates an IBinder service and returns it to the client through onBind()

  • 4. The client uses IBinder to instantiate Messenger (the Handler referring to the service), and then uses messenger to send the Message object to the service

  • 5. The service receives each Message in its Handler (in the handleMessage() method)

The following is a simple service example using Messenger interface. The server process is implemented as follows:

   
  1. package com.zejian.ipctest.messenger;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.Handler;
  5. import android.os.IBinder;
  6. import android.os.Message;
  7. import android.os.Messenger;
  8. import android.util.Log;
  9. /**
  10. * Created by zejian
  11. * Time 2016/10/3.
  12. * Description:Messenger Server simple instance, server process
  13. */
  14. public class MessengerService extends Service {
  15. /** Command to the service to display a message */
  16. static final int MSG_SAY_HELLO = 1;
  17. private static final String TAG = "wzj" ;
  18. /**
  19. * Used to receive data passed from the client
  20. */
  21. class IncomingHandler extends Handler {
  22. @Override
  23. public void handleMessage (Message msg) {
  24. switch (msg.what) {
  25. case MSG_SAY_HELLO:
  26. Log.i(TAG, "thanks,Service had receiver message from client!");
  27. break;
  28. default:
  29. super.handleMessage(msg);
  30. }
  31. }
  32. }
  33. /**
  34. * Create Messenger and pass in the Handler instance object
  35. */
  36. final Messenger mMessenger = new Messenger( new IncomingHandler());
  37. /**
  38. * When binding a Service, this method is called and an implementation will be returned through mmsmessenger
  39. * IBinder Instance object of interface
  40. */
  41. @Override
  42. public IBinder onBind (Intent intent) {
  43. Log.i(TAG, "Service is invoke onBind");
  44. return mMessenger.getBinder();
  45. }
  46. }

  first, we also need to create a Service class MessengerService inherited from Service, and create an IncomingHandler object inherited from Handler to receive messages sent by the client process and process messages through its handleMessage(Message msg). Then create a Messenger object through the IncomingHandler object, which is a special object interacting with the client, and then return the underlying Binder of the Messenger object in the onBind of the Service. Let's take a look at the implementation of the client process:

   
  1. package com.zejian.ipctest.messenger;
  2. import android.app.Activity;
  3. import android.content.ComponentName;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.ServiceConnection;
  7. import android.os.Bundle;
  8. import android.os.IBinder;
  9. import android.os.Message;
  10. import android.os.Messenger;
  11. import android.os.RemoteException;
  12. import android.util.Log;
  13. import android.view.View;
  14. import android.widget.Button;
  15. import com.zejian.ipctest.R;
  16. /**
  17. * Created by zejian
  18. * Time 2016/10/3.
  19. * Description: Clients interacting with the server
  20. */
  21. public class ActivityMessenger extends Activity {
  22. /**
  23. * Messenger interacting with server
  24. */
  25. Messenger mService = null;
  26. /** Flag indicating whether we have called bind on the service. */
  27. boolean mBound;
  28. /**
  29. * Implement the object linked with the server
  30. */
  31. private ServiceConnection mConnection = new ServiceConnection() {
  32. public void onServiceConnected (ComponentName className, IBinder service) {
  33. /**
  34. * Create the corresponding Messenger through the IBinder object passed by the server
  35. * Interact with the server through the Messenger object
  36. */
  37. mService = new Messenger(service);
  38. mBound = true;
  39. }
  40. public void onServiceDisconnected (ComponentName className) {
  41. // This is called when the connection with the service has been
  42. // unexpectedly disconnected -- that is, its process crashed.
  43. mService = null;
  44. mBound = false;
  45. }
  46. };
  47. public void sayHello (View v) {
  48. if (!mBound) return;
  49. // Create a Message entity that interacts with the service Message
  50. Message msg = Message.obtain( null, MessengerService.MSG_SAY_HELLO, 0, 0);
  51. try {
  52. //send message
  53. mService.send(msg);
  54. } catch (RemoteException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. @Override
  59. protected void onCreate (Bundle savedInstanceState) {
  60. super.onCreate(savedInstanceState);
  61. setContentView(R.layout.activity_messenager);
  62. Button bindService= (Button) findViewById(R.id.bindService);
  63. Button unbindService= (Button) findViewById(R.id.unbindService);
  64. Button sendMsg= (Button) findViewById(R.id.sendMsgToService);
  65. bindService.setOnClickListener( new View.OnClickListener() {
  66. @Override
  67. public void onClick (View v) {
  68. Log.d( "zj", "onClick-->bindService");
  69. //The current Activity is bound to the server
  70. bindService( new Intent(ActivityMessenger. this, MessengerService.class), mConnection,
  71. Context.BIND_AUTO_CREATE);
  72. }
  73. });
  74. //Send message to server
  75. sendMsg.setOnClickListener( new View.OnClickListener() {
  76. @Override
  77. public void onClick (View v) {
  78. sayHello(v);
  79. }
  80. });
  81. unbindService.setOnClickListener( new View.OnClickListener() {
  82. @Override
  83. public void onClick (View v) {
  84. // Unbind from the service
  85. if (mBound) {
  86. Log.d( "zj", "onClick-->unbindService");
  87. unbindService(mConnection);
  88. mBound = false;
  89. }
  90. }
  91. });
  92. }
  93. }

   in the client process, we need to create a ServiceConnection object, which represents the link with the server. When calling the bindService method to bind the current Activity to the MessengerService, the onServiceConnected method is called to construct the Messenger object interacting with the server by using the underlying Binder object passed by the server, and then create the Message entity Message interacting with the Service, Encapsulate the information to occur in the Message and send it to the server through the Messenger instance object. ServiceConnection, bindService method and unbindService method have been analyzed before and will not be repeated here. Finally, we need to declare Service and Activity in the manifest file. To test the interaction of different processes, we need to put the Service in a separate process. Therefore, the Service declaration is as follows:

   
  1. <service android:name=".messenger.MessengerService"
  2. android:process= ":remote"
  3. />
  • 1
  • 2
  • 3

android:process=":remote" means that the Service is created in a separate process. Finally, we run the program, and the results are as follows:
 
   then click bind service several times, then send information to the server, and finally unbind. The Log is printed as follows:

   from the above example, it can be seen that the Service server does receive the information sent by the client, and the data must be encapsulated in Message for data transmission in Messenger, because both Message and messenger implement the Parcelable interface, which can easily transfer data across processes (for the Parcelable interface, see another blog article: Analysis of parallelable and Serializable of serialization and deserialization )The information carriers that Message can deliver are what,arg1,arg2,Bundle and replyTo. As for the object field, it is very practical for data transmission in the same process, but it is quite embarrassing for communication between processes. In android 2 2 ago, object did not support cross process transmission, but even android 2 2 after that, we can only pass the objects that implement the Parcelable interface provided by the android system, that is, the objects that implement the Parcelable interface through customization cannot be passed through the object field, so the practicability of the object field becomes quite low in cross process. Fortunately, however, we also have a Bundle object, which can support a large number of data types. Next, from the Log, we can see that the calling sequence of their life cycle methods is basically the same, that is, onCreate(), onBind, onUnBind and onDestroy, whether using the implementation of extended Binder class or Messenger, and onBind() is called only for the first time in multiple bindings. OK ~, the above example demonstrates how to interpret the messages sent by the client at the server, but sometimes we may need the server to respond to the client. At this time, we need to provide two-way messaging. Here is a simple example of two-way messaging between the server and the client.  
   let's take a look at the modification of the server. On the server, we just need to modify the IncomingHandler and reply a message to the client after receiving the message.

   
  1. /**
  2. * Used to receive data passed from the client
  3. */
  4. class IncomingHandler extends Handler {
  5. @Override
  6. public void handleMessage( Message msg) {
  7. switch (msg.what) {
  8. case MSG_SAY_HELLO:
  9. Log.i( TAG, "thanks,Service had receiver message from client!");
  10. //Reply to the client information, and the object is passed by the client
  11. Messenger client=msg.replyTo;
  12. //Get message entity of reply information
  13. Message replyMsg= Message.obtain( null, MessengerService. MSG_SAY_HELLO);
  14. Bundle bundle= new Bundle();
  15. bundle.putString( "reply", "ok~,I had receiver message from you! ");
  16. replyMsg.setData(bundle);
  17. //Send message to client
  18. try {
  19. client.send(replyMsg);
  20. } catch ( RemoteException e) {
  21. e.printStackTrace();
  22. }
  23. break;
  24. default:
  25. super.handleMessage(msg);
  26. }
  27. }
  28. }

   then modify the client. In order to receive the reply from the server, the client also needs a Messenger and Handler to receive messages. Its implementation is as follows:

   
  1. /**
  2. * Used to receive the information returned by the server
  3. */
  4. private Messenger mRecevierReplyMsg= new Messenger( new ReceiverReplyMsgHandler());
  5. private static class ReceiverReplyMsgHandler extends Handler{
  6. private static final String TAG = "zj";
  7. @Override
  8. public void handleMessage (Message msg) {
  9. switch (msg.what) {
  10. //Receive server reply
  11. case MessengerService.MSG_SAY_HELLO:
  12. Log.i(TAG, "receiver message from service:"+msg.getData().getString( "reply"));
  13. break;
  14. default:
  15. super.handleMessage(msg);
  16. }
  17. }
  18. }

   in addition to adding the above code, it is also necessary to pass the Messenger receiving the reply from the server to the server through the replyTo parameter of the Message when sending the Message, so as to serve as a bridge for students. The code is as follows:

   
  1. public void sayHello(View v) {
  2. if (!mBound) return;
  3. // Create a Message entity that interacts with the service Message
  4. Message msg = Message.obtain( null, MessengerService.MSG_SAY_HELLO, 0, 0);
  5. //Pass the Messenger receiving the reply from the server to the server through the replyTo parameter of Message
  6. msg.replyTo=mRecevierReplyMsg;
  7. try {
  8. //send message
  9. mService.send(msg);
  10. } catch (RemoteException e) {
  11. e.printStackTrace();
  12. }
  13. }

   ok ~, the simple example of two-way message transmission between the server and the client has been modified. Let's run the code and see the Log printing, as follows:

   it can be seen from the Log that the server and client have indeed received information respectively. Now we have analyzed the way of cross process communication through messenger. Finally, in order to help you understand, here is a schematic diagram of inter process communication through messenger:

4.3 notes on binding services

  1. Multiple clients can connect to a service at the same time. However, only when the first client binds will the system call the onBind() method of the service to retrieve the IBinder. Bind bind() to the same client again without calling the same client. When the last client unbinds the service, the system destroys the service (unless startService() also starts the service).

  2. In general, we should set binding and unbinding operations at the time of bringing up and teardown of the client life cycle (such as the life cycle of Activity) in order to control the Service in the binding state. Generally, there are the following two cases:

  • If you only need to interact with the service when the Activity is visible, you should bind it during onStart() and unbind it during onStop().

  • If you want the Activity to still receive responses when it stops running in the background, you can bind it during onCreate() and unbind it during onDestroy(). It should be noted that this means that the Activity needs to use the service throughout its running process (even during background running). Therefore, if the service is located in other processes, the system is likely to terminate the process when the weight of the process is increased.

  3. In general (note), do not bind or unbind during onResume() and onPause() of an Activity, because these callbacks will occur every life cycle transition, so it is unreasonable to bind and unbind repeatedly. In addition, if multiple activities in the application are bound to the same service and conversion occurs between two activities, if the current Activity is unbound (suspended) before the next binding (recovery period), the system may destroy the service and rebuild the service. Therefore, the binding of the service should not occur in onResume() and onPause() of the Activity.

  4. We should always catch the DeadObjectException. The DeadObjectException exception is raised when the connection is interrupted, indicating that the calling object has died, that is, the Service object has been destroyed. This is the only exception raised by the remote method. The DeadObjectException inherits from RemoteException, so we can also catch the RemoteException exception.

  5. The application component (client) can be bound to the service by calling bindService(). The Android system then calls the onBind() method of the service, which returns the IBinder used for interacting with the service, which is executed asynchronously. Base note:

5. About the conversion between startup service and binding service

   through the previous analysis of the two Service states, I believe you have a relatively clear understanding of the two Service states. Now let's analyze what happens when the startup state and binding state exist at the same time?  
   although there are two states of a Service: startup and binding, in fact, a Service can be in both States, that is, it can be either a startup Service (running indefinitely) or a binding Service. It should be noted that the Android system will only create an instance object for one Service, so whether it is to start the Service or bind the Service, the operation is the same Service instance, and the following two situations will occur due to the execution sequence of bind Service or start Service:

  • Bind the service before starting the service

       if the current Service instance runs in the bound state first and then in the started state, the bound Service will turn to the started Service. At this time, if the previously bound host (Activity) is destroyed, it will not affect the operation of the Service. The Service will continue to run continuously. Specify that the Service will be destroyed only when the call is received to stop the Service or there is insufficient memory.

  • Start the service before binding the service

       if the current Service instance runs in the startup state first and then in the binding state, the current startup Service will not be converted to the binding Service, but will still be bound with the host. Only after the host is unbound, the Service will still run in the background according to the life cycle of the startup Service. The Service will not be destroyed until the Context calls stopService() or the Service itself calls stopSelf() method or there is insufficient memory.

  the above two cases show that the priority of starting the Service is indeed higher than that of binding the Service. However, no matter whether the Service is in the startup or binding state, or in the startup and binding state, we can use the Service by calling Intent like using Activity (even if the Service comes from another application). Of course, we can also declare the Service as a private Service through the manifest file to prevent other applications from accessing it. Finally, there is something special to note here. Since the Service runs in the main thread of its managed process (UI thread), it neither creates its own thread nor runs in a separate process (unless otherwise specified). This means that if the Service will perform any time-consuming events or blocking operations (such as MP3 playback or networking), a new thread should be created within the Service to complete this work. In short, the time-consuming operations should be executed by another thread. Only by using a separate thread can the risk of "application non response" (ANR) errors be reduced, so that the main thread of the application can focus on the interaction between the user and the Activity, so as to achieve a better user experience.

6. Front desk service and notification sending

   the foreground service is considered to be a service that users are actively aware of, so the system will not consider terminating it when there is insufficient memory. The foreground service must provide notifications to the status bar, which is located under the "in progress" heading, which means that notifications cannot be cleared unless the service is stopped or deleted from the foreground. For example, a music player that plays music from a service is set to run in the foreground because the user is clearly aware of its operation. The notification in the status bar may indicate the song being played and allow the user to start the Activity to interact with the music player. If we need to set the service to run in the foreground, how can we achieve it? Android official provides us with two methods, startforegroup() and stopforegroup(), which are parsed as follows:

  • startForeground(int id, Notification notification) 
    The function of this method is to set the current service as the foreground service, where the ID parameter represents the integer number that uniquely identifies the notification. It should be noted that the integer id provided to startforegroup() must not be 0, and notification is a notification in the status bar.

  • stopForeground(boolean removeNotification) 
    This method is used to delete a service from the foreground. This method passes in a Boolean value to indicate whether the status bar notification is also deleted. true means delete. Note that this method does not stop the service. However, if the service is stopped while it is running in the foreground, the notification is also deleted.

Let's use the above two methods in combination with a simple case. The foreroundservice code is as follows:

   
  1. package com.zejian.ipctest.foregroundService;
  2. import android.app.Notification;
  3. import android.app.Service;
  4. import android.content.Intent;
  5. import android.graphics.BitmapFactory;
  6. import android.os.IBinder;
  7. import android.support.annotation.Nullable;
  8. import android.support.v4.app.NotificationCompat;
  9. import com.zejian.ipctest.R;
  10. /**
  11. * Created by zejian
  12. * Time 2016/10/4.
  13. * Description:Start foreground service Demo
  14. */
  15. public class ForegroundService extends Service {
  16. /**
  17. * id Cannot be set to 0, otherwise it cannot be set to foreground service
  18. */
  19. private static final int NOTIFICATION_DOWNLOAD_PROGRESS_ID = 0x0001;
  20. private boolean isRemove= false; //Need to remove
  21. /**
  22. * Notification
  23. */
  24. public void createNotification (){
  25. //Use compatible version
  26. NotificationCompat.Builder builder= new NotificationCompat.Builder( this);
  27. //Set notification icon for status bar
  28. builder.setSmallIcon(R.mipmap.ic_launcher);
  29. //Set the icon of the notification bar bar bar
  30. builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.screenflash_logo));
  31. //Users are not allowed to click the delete button to delete
  32. builder.setAutoCancel( false);
  33. //Prohibit sliding deletion
  34. builder.setOngoing( true);
  35. //Time display in the upper right corner
  36. builder.setShowWhen( true);
  37. //Set the title and content of the notification bar
  38. builder.setContentTitle( "I am Foreground Service!!!");
  39. //Create notification
  40. Notification notification = builder.build();
  41. //Set as foreground service
  42. startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID,notification);
  43. }
  44. @Override
  45. public int onStartCommand (Intent intent, int flags, int startId) {
  46. int i=intent.getExtras().getInt( "cmd");
  47. if(i== 0){
  48. if(!isRemove) {
  49. createNotification();
  50. }
  51. isRemove= true;
  52. } else {
  53. //Remove foreground service
  54. if (isRemove) {
  55. stopForeground( true);
  56. }
  57. isRemove= false;
  58. }
  59. return super.onStartCommand(intent, flags, startId);
  60. }
  61. @Override
  62. public void onDestroy () {
  63. //Remove foreground service
  64. if (isRemove) {
  65. stopForeground( true);
  66. }
  67. isRemove= false;
  68. super.onDestroy();
  69. }
  70. @Nullable
  71. @Override
  72. public IBinder onBind (Intent intent) {
  73. return null;
  74. }
  75. }

   in the ForegroundService class, a notification notification is created, and the parameters passed when starting the Service determine whether to start or close the foreground Service. Finally, when the onDestroy method is called, the foreground Service should also be removed. The following is the implementation of foreroundactivity:

   
  1. package com.zejian.ipctest.foregroundService;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import com.zejian.ipctest.R;
  8. /**
  9. * Created by zejian
  10. * Time 2016/10/4.
  11. * Description:
  12. */
  13. public class ForegroundActivity extends Activity {
  14. @Override
  15. protected void onCreate (Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_foreground);
  18. Button btnStart= (Button) findViewById(R.id.startForeground);
  19. Button btnStop= (Button) findViewById(R.id.stopForeground);
  20. final Intent intent = new Intent( this,ForegroundService.class);
  21. btnStart.setOnClickListener( new View.OnClickListener() {
  22. @Override
  23. public void onClick (View v) {
  24. intent.putExtra( "cmd", 0); //0, turn on the front desk service, 1, turn off the front desk service
  25. startService(intent);
  26. }
  27. });
  28. btnStop.setOnClickListener( new View.OnClickListener() {
  29. @Override
  30. public void onClick (View v) {
  31. intent.putExtra( "cmd", 1); //0, turn on the front desk service, 1, turn off the front desk service
  32. startService(intent);
  33. }
  34. });
  35. }
  36. }

   the code is relatively simple. Let's run the program directly to see the results:

   ok ~, the above is about the Service foreground Service. Next, let's talk about the difference between Service and thread

7. Difference between Service and Thread

  • The two concepts are quite different

    • Thread is the smallest unit of program execution. It is the basic unit of CPU allocation. UI thread in android system is also a kind of thread. Of course, thread can also be used to perform some time-consuming asynchronous operations.

    • Service is a mechanism of Android. The service runs on the main thread and is hosted by the system process. The communication between it and other components is similar to client and server. It is a kind of lightweight IPC communication. The carrier of this communication is binder. It is an IPC for exchanging information in the linux layer, and the so-called service background task only refers to components without UI.

  • The implementation tasks of the two are very different

    • In android system, thread generally refers to the working thread (i.e. background thread), and the main thread is a special working thread, which is responsible for assigning events to corresponding user interface gadgets, such as drawing events and event response. Therefore, in order to ensure that the response of the application UI can force the main thread to perform time-consuming operations. If the actions you perform cannot be completed quickly, make sure they are executed on a separate worker thread.

    • Service is a component in the android system. Generally, it runs in the main thread, so it can't perform time-consuming operations in service, otherwise the system will report ANR exception. Most of the reason why service is called background service is that it has no UI and users can't perceive it (of course, some means can also be used to let users know), but if you need to let service perform time-consuming tasks, You can start a separate thread in the service to execute.

  • Both usage scenarios

    • When you want to execute time-consuming network or database queries and other tasks that block UI threads or use CPU intensively, you should use worker threads to ensure that UI threads are not occupied and affect the user experience.

    • In an application, if you need to run in the background for a long time and do not need interaction, use services. For example, playing music is performed in the background through Service+Notification and displayed in the notification bar.

  • The best way to use both

    In most cases, Thread and Service will be used together. For example, downloading files will generally be executed in the background through Service + Notification, and + Thread will be displayed in the Notification bar for asynchronous download. For another example, the application will maintain a Service to obtain push services from the network. In the official view of Android, the same is true. Therefore, the official website provides a combination of Thread and Service to facilitate us to perform time-consuming tasks in the background. It is IntentService. (if you want to know more about IntentService, you can see another article of the blogger: Full explanation of IntentService for Android multithreading )Of course, IntentService is not applicable to all scenarios, but its advantages are easy to use and concise code. We do not need to create Service instances and threads at the same time. It is still very good in some scenarios! Because IntentService is a single worker thread, tasks need to be queued, so it is not suitable for most multitasking situations.

  • The real relationship between the two

    • The two have nothing to do with half a cent.

8. Manage the service life cycle

   as for the execution sequence of the Service life cycle method, we have analyzed it almost. Here is a new execution flow chart (from the Android official website)
 
  the left figure shows the life cycle of the Service created using startService(), and the right figure shows the life cycle of the Service created using bindService(). Through the life cycle method in the figure, we can monitor the overall execution process of the Service, including creation, operation and destruction. The method callback in different states of the Service has been clearly described in the previous analysis, which will not be repeated here. The original description of the life cycle on the official website is given below:

  the whole life cycle of the service starts from the call of onCreate() and ends when onDestroy() returns. Similar to Activity, the service completes the initial setting in onCreate() and releases all remaining resources in onDestroy(). For example, a music playback service can create a thread for playing music in onCreate() and then stop the thread in onDestroy().  
  onCreate() and onDestroy() methods will be called for all services regardless of whether the service is created through startService() or bindService().  
  the effective life cycle of the service starts with calling onStartCommand() or onBind() methods. Each method has an Intent object, which is passed to startService() or bindService() respectively.  
  for starting a service, the effective life cycle ends at the same time as the whole life cycle (even after onStartCommand() returns, the service is still active). For binding services, the valid life cycle ends when onUnbind() returns.

  from the execution flow chart, the service life cycle is much simpler than the Activity life cycle. However, we must pay close attention to how to create and destroy services, because services can run in the background without users' awareness. There are two situations in the life cycle of management services (from creation to destruction):

  • Start service
    The service is created when other components call startService(), then runs indefinitely, and must be stopped from the line by calling stopSelf(). In addition, other components can also stop the service by calling stopService(). After the service is stopped, the system will destroy it.

  • Binding service
    This service is created when another component (client) calls bindService(). Then, the client communicates with the service through the IBinder interface. The client can close the connection by calling unbindService(). Multiple clients can bind to the same service, and the system will destroy the service after all bindings are cancelled. (the service does not have to stop running by itself)

   although we can manage the service life cycle through the above two cases, we must also consider another case, that is, the combination of starting service and binding service, that is, we can bind to the service that has been started using startService(). For example, you can start the background music service by calling startservice () using Intent (identify the music to play). Then, when the user needs to control the player slightly or obtain information about the currently playing song, the Activity can bind to the service by calling bindService(). In this case, stopService() or stopSelf() will not actually stop the service unless all clients are unbound. Therefore, in this case, we need special attention.

9. Implicit startup problems above Android 5.0

Since there is implicit startup, there will be display startup. Let's first understand what implicit startup and display startup are.

  • Display start
    Directly on the code at a glance, do not explain.
   
  1. //Display start
  2. Intent intent = new Intent( this,ForegroundService. class);
  3. startService(intent);

  • Implicit start
    An Action needs to be set. We can set the name of the Action to the full path name of the Service. In this case, android:exported defaults to true.
   
  1. final Intent serviceIntent= new Intent(); serviceIntent.setAction( "com.android.ForegroundService");
  2. startService(serviceIntent);

  • Meaning of existence
    If in the same application, both can be used. In different applications, you can only start implicitly.

  • Implicit startup problems for Android 5.0 and above
      after Android 5.0, google banned the implicit declaration of Intent to start the Service for security reasons. If the Service is started implicitly, there will be an error that does not indicate Intent, as follows:

       the main reason can be found in the source code. Here we look at the validateServiceIntent(Intent service) in the ContextImpl source code of Android 4.4. It can be seen that if the component and package of the intent to start the service are empty and the version is greater than KITKAT, only an alarm will be sent out to tell the developer to implicitly declare that it is unsafe for intent to start the service  

      and in android 5 After 0? We're looking at android 6 The source code of 0 is as follows (sublime text check the source code of android versions is cool!!):  

       from the source code, we can see that if the component and package of the intent ion of starting the service are empty and the version is greater than LOLLIPOP(5.0), an exception will be thrown directly. This exception is consistent with the exception reported in the previous implicit startup. So how to solve it?

  • Solution

    • Set Action and packageName
         
    1. final Intent serviceIntent= new Intent(); serviceIntent.setAction( "com.android.ForegroundService");
    2. serviceIntent.setPackage(getPackageName()); //Set the package name of the application
    3. startService(serviceIntent);

    • Convert implicit startup to display startup
         
    1. public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
    2. // Retrieve all services that can match the given intent
    3. PackageManager pm = context.getPackageManager();
    4. List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
    5. // Make sure only one match was found
    6. if (resolveInfo == null || resolveInfo.size() != 1) {
    7. return null;
    8. }
    9. // Get component info and create ComponentName
    10. ResolveInfo serviceInfo = resolveInfo. get( 0);
    11. String packageName = serviceInfo.serviceInfo.packageName;
    12. String className = serviceInfo.serviceInfo.name;
    13. ComponentName component = new ComponentName(packageName, className);
    14. // Create a new intent. Use the old one for extras and such reuse
    15. Intent explicitIntent = new Intent(implicitIntent);
    16. // Set the component to be explicit
    17. explicitIntent.setComponent(component);
    18. return explicitIntent;
    19. }

    The calling method is as follows:

         
    1. Intent mIntent= new Intent(); //Auxiliary Intent
    2. mIntent.setAction( "com.android.ForegroundService");
    3. final Intent serviceIntent= new Intent(getExplicitIntent( this,mIntent));
    4. startService(serviceIntent);

    This problem is perfectly solved.

10. How to ensure that the service is not killed

   in fact, this method is not recommended, but since we talked about it, let's give some implementation ideas here. It is mainly divided into the following three situations

  • Killing Service due to insufficient memory resources
    This situation is easy to handle. You can set the return value of onStartCommand() method to start_ Stick or START_REDELIVER_INTENT, which means that the Service is killed when the memory resources are tight, and then restored when the memory resources are sufficient. You can also set the Service as the foreground Service, which has a higher priority and will not be killed when memory resources are tight. We have analyzed and implemented the implementation of these two points before, so we won't repeat it here. The simple code is as follows:
   
  1. /**
  2. * Return to start_ Stick or START_REDELIVER_INTENT
  3. * @param intent
  4. * @param flags
  5. * @param startId
  6. * @return
  7. */
  8. @Override
  9. public int onStartCommand (Intent intent, int flags, int startId) {
  10. // return super.onStartCommand(intent, flags, startId);
  11. return START_STICKY;
  12. }

  • The user kills the Service by setting - > Apps - > running - > stop
    This situation is manually intervened by the user, but fortunately, this process will execute the service life cycle, that is, the onDestory method will be called. At this time, you can send A broadcast restart in onDestory(). This will start immediately after killing the service. This scheme is feasible, but in order to improve the program, we can start two services to monitor and start each other. Service A listens to B's broadcast to start B, and service B listens to A's broadcast to start A. The code implementation of the first method is given here as follows:
   
  1. package com.zejian.ipctest.neverKilledService;
  2. import android.app.Service;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.IntentFilter;
  7. import android.os.IBinder;
  8. import android.support.annotation.Nullable;
  9. /**
  10. * Created by zejian
  11. * Time 2016/10/4.
  12. * Description:The user kills the Service by setting - > Apps - > running - > stop
  13. */
  14. public class ServiceKilledByAppStop extends Service{
  15. private BroadcastReceiver mReceiver;
  16. private IntentFilter mIF;
  17. @Nullable
  18. @Override
  19. public IBinder onBind (Intent intent) {
  20. return null;
  21. }
  22. @Override
  23. public void onCreate () {
  24. super.onCreate();
  25. mReceiver = new BroadcastReceiver() {
  26. @Override
  27. public void onReceive (Context context, Intent intent) {
  28. Intent a = new Intent(ServiceKilledByAppStop. this, ServiceKilledByAppStop.class);
  29. startService(a);
  30. }
  31. };
  32. mIF = new IntentFilter();
  33. //Custom action
  34. mIF.addAction( "com.restart.service");
  35. //Register broadcast receiver
  36. registerReceiver(mReceiver, mIF);
  37. }
  38. @Override
  39. public void onDestroy () {
  40. super.onDestroy();
  41. Intent intent = new Intent();
  42. intent.setAction( "com.restart.service");
  43. //Send broadcast
  44. sendBroadcast(intent);
  45. unregisterReceiver(mReceiver);
  46. }
  47. }

  • The user forcibly kills the Service through settings - > Apps - > downloaded - > force stop
    This method is tragic because it directly kill s the program and does not follow the life cycle process. In the first two cases, as long as Force Stop is executed, it will be abandoned. In other words, in this case, the service cannot be restarted, or the Force Stop can only be set, but it is unnecessary. It is too rogue....

ok ~, the above is the solution to ensure that the Service will not be killed in a certain scenario. For the third case, if there is a solution, please leave a message. ok, that's the end of all the introduction about Service.  


Main references:
https://developer.android.com/guide/components/services.html#Notifications 
https://developer.android.com/guide/components/processes-and-threads.html 
https://developer.android.com/guide/components/bound-services.html#Lifecycle 
http://blog.csdn.net/vrix/article/details/45289207 
Exploration of android development Art

Tags: Android

Posted by r_a_s_robin on Sat, 16 Apr 2022 09:56:58 +0930