Services in the manifest file

A service is a component that can operate in the background for a long time without providing a user interface. Components can bind to services, interact with them, and even conduct interprocess communication (IPC), for example, services can handle network transactions, play music, perform file I/O, or interact with content providers, all in the background.

There are two ways to start the service:

startService

When a component starts a Service using startService, the Service is in the started state. Once started, the Service can run in the background indefinitely, even if the component that started the Service has been destroyed. A started service typically performs a single operation and does not return the result to the caller. For example, it might download or upload files over the network. After the operation is complete, the service stops automatically.

bindService

When a component binds a Service through bindService, the Service is in a bound state. Binding services provide a server-side to client interface that allows components to interact with services, send requests, get results, and even perform these operations using interprocess communication (IPC). Multiple components can bind the service together, and when all are cancelled, the service will be destroyed.

1. The Service is declared in the manifest file

< service android:enabled=["true" | "false"] 
         android:exported=["true" | "false"] 
         android:icon="drawable resource" 
         android:isolatedProcess=["true" | "false"] 
         android:label="string resource" 
         android:name="string" 
         android:permission="string" 
         android:process="string"  >  
    . . . 
< /service > 
Copy the code

Element attribute description:

The property name role
android:enabled Whether the service can be instantiated by the system. The default true
android:exported Whether components of other applications can start or interact with services.

The default value depends on whether the Service component is includedintent-filterElements,

If no, the service cannot be called by other applications, that is, false. And true.
android:isolatedProcess If set to true, the service will run in a special process.

This process is isolated from the rest of the system and does not have its own permissions.

The only means of communication is through the Service API (binding and startup).
android:process Typically, all components of an application run in the default process that was created. The process name is the same as the package name.

If the name set by this property begins with a colon (‘ : ‘), a new process that is private to the program will be created if necessary, and the service will run in that new process.

If the process name begins with a lowercase letter, the service will run in a global process with that name and will be granted access. This allows multiple components belonging to different applications to share the same process to reduce resource usage.

2. To create a Service

2.1 Service Life Cycle Callback

Creating a Service requires inheriting the Service and overwriting some callback methods to handle the Service life cycle.

onStartCommand()

This method is called when a component (Activity) requests to start a service via startService(). The service can be stopped by calling stopSelf() or stopService() after the work is done. In this method, the int flags argument returned has three types, representing different meanings:

1. START_STICKY

When a Service is killed and its memory is idle, the system attempts to recreate the Service. Once the Service is successfully created, the onStartCommand method is called back, but the Intent is null. Such as PendingIntent, this state is suitable for media players or similar services that do not execute a command, but run indefinitely and wait for a job.

2. START_NOT_STICKY

If a Service is killed by the system because of insufficient memory, the system does not attempt to recreate the Service even if the system memory is free again. Unless startService is called again in the program to start the Service, this is the safest option to avoid running the Service when it is not necessary and when the application can easily restart all outstanding jobs.

3. START_REDELIVER_INTENT

When a Service is killed by the system for running out of memory, the Service is rebuilt and onStartCommand() is called with the last Intent passed to the Service. Any pending Intent is passed in order. Unlike START_STICKY, the Intent passed will be non-empty, the last time the Intent in startService was called. This value applies to services that actively perform jobs that should be recovered immediately, such as downloading files.

onBind()

This method is called back when a component (Activity) binds to a service via bindService(). This method must return an interface provided by the IBinder for the client and server to communicate. If not bound, null can be returned

onCreate()

This method is called back when the service is first created. If the service is already running, this method is not called back.

onDestroy()

The system calls this method when the service is no longer in use and is about to be destroyed. The service should implement this method to clean up all resources such as threads, registered listeners, sinks, and so on. This is the last call received by the service.

2.2 Through InheritanceService IntentServiceCreate a Service

Service

This is the base class that applies to all services. By default, the service uses the main thread of the application, which degrades the performance of all activities that the application is running.

IntentService

This is a subclass of Service that uses a worker thread to process all start requests one by one. This is best if you don’t need a Service to handle multiple requests at the same time. IntentService provides the default implementation of onStartCommand(), which sends the Intent to the work queue and the onHandleIntent() implementation in turn. All you need to do is implement the onHandleIntent() method, which receives each Intent that launches the request, enabling you to do background work. Stop the service after all start requests have been processed without calling stopSelf().

IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) IntentService (ServiceHandler) In the onStart method, send a message to ServiceHandler. The message sent in the onStartCommand method is received in ServiceHandler, the onHandleIntent() callback is called, and the service is closed with stopSelf(msg.arg1).

BindService does not call onHandleIntent() when it launches an IntentService. BindService does not call onStartCommand when it launches an IntentService.

The following specific source code:

1. Create ServiceHandler in the onCreate method

    @Override
    public void onCreate() {
        

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
Copy the code
  1. Send a message in the onStart method
 @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

Copy the code
  1. ServiceHandler processes the message and stops the service.
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
Copy the code

3. Service example

3.1 Inherited from IntentService

1. Register the Service component in the AndroidManifest file

<service android:name=".service.HelloIntentService" />
Copy the code

2. Create a Service inherited from IntentService

public class HelloIntentService extends IntentService {

    private static final String TAG = "HelloIntentService";

    public HelloIntentService() {
        super("HelloIntentService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        try {
            Log.e(TAG, "onHandleIntent: lll"); Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); }}}Copy the code

3. Start the Service in the component

 startService(new Intent(this, HelloIntentService.class));
Copy the code

3.2 Inheriting from Service

1. startService

public class HelloService extends Service {

    private static final String TAG = "HelloService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: lll");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: lll ");
        return super.onStartCommand(intent, flags, startId);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: lll ");
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind: lll");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: lll"); super.onDestroy(); }}Copy the code

2. bindService

Create a Service

public class LocalService extends Service {

    private LocalBinder binder = new LocalBinder();
    private final Random mGenerator = new Random();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    public class LocalBinder extends Binder {

        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

    public int getRandomNumber() {
        returnmGenerator.nextInt(100); }}Copy the code

Binding Service

bindService(new Intent(this, LocalService.class), new ServiceConnection() {


                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {
                        LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
                        LocalService mService = binder.getService();
                        Toast.makeText(ServiceActivity.this, "LocalService getRandomNumber = " +  mService.getRandomNumber(), Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onServiceDisconnected(ComponentName name) {

                    }
}, Service.BIND_AUTO_CREATE);
Copy the code

3.3 Using Messenger to simplify client-server interaction

When performing IPC, it is simpler to use Messenger for the interface than to implement it using AIDL, because Messenger queues all service calls, whereas a pure AIDL interface sends multiple requests simultaneously to the service, which then has to deal with multi-threading.

For most applications, the service does not need to perform multithreading, so using Messenger lets the service handle one call at a time. If the service must perform multithreading, then AIDL should be used to define the interface.

Messenger to achieve communication steps:

  • The Service implements a Handler that receives a callback for each invocation from the client
  • Handler is used to create Messenger objects (a reference to Handler)
  • Messenger creates an IBinder and the service returns it to the client via onBind()
  • The client instantiates Messenger (the Handler that references the service) using IBinder, which then sends the Message object to the service
  • The service receives each Message in its Handler (specifically, in the handleMessage() method).

Use Messenger communication instances

  1. The server MessengerService code inherits Service and overrides the onBind() method.
  • Create a ClientIncomingHandler to receive client messages
  • Create a Messager object using IncomingHandler
  • The IBinder generated by Messager is returned to the client in the onBind method
public class MessengerService extends Service { /** * Command to the service to display a message */ public static final  int MSG_SAY_HELLO = 1; public static final int MSG_SAY_HELLO_REPLY = 2; private class ClientIncomingHandler extends Handler { @Override public void handleMessage(Message msg) { Log.e(TAG,"handleMessage: lll msg = " + msg.what);
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); // Get the client's Messenger object and send it a message Messenger client = msg.replyto; try { Message message = Message.obtain(); message.arg1 = new Random().nextInt(100); message.what = MSG_SAY_HELLO_REPLY; client.send(message); } catch (RemoteException e) { e.printStackTrace(); }break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: lll ");
        returnmMessenger.getBinder(); }}Copy the code

2. The client MessengerActivity code:

  • Create a ServiceIncomingHandler to receive service messages
  • To bind the server, obtain the Messager object on the server and initialize the Messager object on the client to respond to the message sent from the server to the client.
Create a ServiceIncomingHandler, Private class ServiceIncomingHandler extends Handler {@override public void handleMessage(Message MSG) { Log.e(TAG,"handleMessage");
            switch (msg.what) {
                case MessengerService.MSG_SAY_HELLO_REPLY:
                    Toast.makeText(MessengerActivity.this, "client received message from service : " + msg.arg1, Toast.LENGTH_SHORT).show();
                    break; default: super.handleMessage(msg); }} // Bind the server. After the binding is successful, obtain the server Messager object and initialize the client Messager object. Private ServiceConnection mConnection = newServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {

            mService = new Messenger(service);
            client = new Messenger(new ServiceIncomingHandler());
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mBound = false; }}; // Send messages to the server public voidsayHello() {
        if(! mBound) {return;
        }
        // Create and send a message to the service, using a supported 'what'value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { msg.replyTo = client; mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); }}Copy the code

Messengeractivity.java

package com.littlezan.interviewpractice.service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Toast; import com.littlezan.interviewpractice.R; /** * ClassName: MessengerActivity * Description: Public class MessengerActivity extends appActivity {public class MessengerActivity extends appactivity { /** * Messengerfor communicating with the service.
     */
    Messenger mService = null;

    Messenger client;

    /**
     * Flag indicating whether we have called bind on the service.
     */
    boolean mBound;

    public static void start(Context context) {
        context.startActivity(new Intent(context, MessengerActivity.class));
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {

            mService = new Messenger(service);
            client = new Messenger(new ServiceIncomingHandler());
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mBound = false; }}; private static final String TAG ="MessengerActivity";


    private class ServiceIncomingHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Log.e(TAG, "handleMessage");
            switch (msg.what) {
                case MessengerService.MSG_SAY_HELLO_REPLY:
                    Toast.makeText(MessengerActivity.this, "client received message from service : " + msg.arg1, Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }



    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messager);

        initView();
    }

    private void initView() {
        findViewById(R.id.btnStartService).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
                bindService(intent, mConnection, Context.BIND_AUTO_CREATE); }}); findViewById(R.id.btnSayHello).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sayHello(); }}); } public voidsayHello() {
        if(! mBound) {return;
        }
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            msg.replyTo = client;
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false; }}}Copy the code