Comprehensive analysis Service of Android components

Keywords: Android xml

preface

Service is a solution to realize the background running of programs in Android, which is very suitable for performing tasks that do not need to interact with users and run for a long time.

main points

  • It depends on the application process in which the service is created, rather than running in a separate process.
  • Time consuming operations need to manually create sub threads within the service and perform specific tasks here. Otherwise, the main thread may be blocked.

life cycle


There are three ways to start a Service:

  • Start service: startService() starts service, stopService() closes service

startService() callback onCreate - > onstartcommand
stopService() callback onDestroy

  • Binding service: bindService() binding service, unbindService() unbinding service. The client communicates with the service through an IBinder interface

bindService() callback onCreate - > onbind
unbindService() callback onUnBind -- > ondestore

  • Mixed mode: start the service first and then bind the service

startService() callback onCreate - > onstartcommand; bindservice() callback onBind,unbindService() callback onunbind; stopservice() callback onDestroy

main points:

  • No matter how many times the service is opened, the onCreate method will only be called once, and the system will only create an instance of the service
  • In the whole life cycle method, only the onStartCommand method can be called multiple times, and other methods can only be called once
  • onStartCommand() calls = startService() calls
  • Multiple clients can be bound to the same service. When all clients are unbound, the system will destroy the service

Summary:

  • startService starts the service, but cannot operate the service
  • bindService can bind services and operate services

Service classification

  1. Divided into local service and remote service by operation location

Local service

It is used inside the application to implement some time-consuming tasks, the most common and commonly used background Service.

example

MyService class

public class MyService extends Service {
     @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("Executed onCreat()");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("Executed onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("Executed onDestory()");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    
    private MyBinder mBinder = new MyBinder();
    class MyBinder extends Binder {
        public String printServiceInfo() {
            return "Activity and Service Establish communication and transfer data";
        }
    }
}

Build the Intent object in Activity, call startService() to start Service, stopService to stop Service, bindService to bind Service, unbindService to unbind Service

@Override
    public void onClick(View view) {
        Intent i = new Intent(MainActivity.this, MyService.class);
        switch (view.getId()) {
            case R.id.btn_start_service:
                startService(i);
                break;
            case R.id.btn_stop_service:
                stopService(i);
                break;
            case R.id.btn_bind_service:
                bindService(i, connection, BIND_AUTO_CREATE);
                break;
            case R.id.btn_unbind_service:
                unbindService(connection);
                break;
   }
}
    private MyService.MyBinder myBinder;

    //Create an anonymous class for ServiceConnection
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //Instantiate the internal class myBinder of the Service
            //Through the downward transformation, an instance of MyBinder is obtained. Binder implements the IBinder interface
            myBinder = (MyService.MyBinder) iBinder;
            //Call the method of Service class in Activity
            String info = myBinder.printServiceInfo();
            System.out.println("---------->" + info);
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };

stay AndroidManifest.xml Register Service in

<service android:name=".MyService" />

The operation result is

Remote service

It can be reused by other applications within Android system, such as weather forecast service. Other applications don't need to write such services anymore, just call the existing ones. Interfaces can be defined and exposed for operation by other applications. The client establishes a connection to the service object and invokes the service through that connection.

step

Server side:

  • Create a new definition AIDL file and declare the interface that the service needs to provide to the client
  • Implement the interface method defined in AIDL in the Service subclass, and define the method of life cycle
  • stay AndroidMainfest.xml Register the service in and declare it as a remote service
Server side instance

Create a new AIDL file, define the contents (Methods) that the Service needs to communicate with the Activity in the new AIDL file, and compile (Make Project)

interface AIDLService {
    /**
     * //AIDL The following data types are supported in
       //1. Basic data type
       //2. String And CharSequence
       //3. List And Map, list and Map object elements must be data types supported by AIDL;
       //4. AIDL Auto generated interface (import import required)
       //5. realization android.os.Parcelable  Class of interface (need to import - import)
     */
    void aidlService();
}


Implement the interface method defined in AIDL in the Service subclass, and define the method of life cycle

public class ServiceDemo extends Service {
    public ServiceDemo() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("-------->onBind");
        return mBinder;
    }
    AIDLService.Stub mBinder = new AIDLService.Stub() {
        @Override
        public void aidlService() throws RemoteException {
            System.out.println("Client passes AIDL Successful communication with remote background");
        }
    };
}

stay AndroidMainfest.xml Register service in & declare as remote service

        <service
            android:name=".service.ServiceDemo"
            android:exported="true" //Settings can be called by other processes
            android:process=":remote">//Set local service to remote service
            <intent-filter>
                 // Here, the action of Intent must be written as "Server package name. aidl filename"
                <action android:name="com.xf.AIDLService"/>
            </intent-filter>
        </service>

client:

  • Copy the AIDL file of the server to the directory
  • use Stub.asInterface Interface gets the Binder of the server, and calls the interface method provided by the service as required
  • Specify the Service name and package of the server through Intent, and bind the remote Service
Client instance

Copy the package containing the AIDL file of the server to the client directory (Project/app/src/main), and compile it

In Activity, use Stub.asInterface Interface gets the Binder of the server; specifies the Service name and package of the server through Intent to bind the Service; calls the interface method provided by the Service as required.

  // Open service
  case R.id.btn_remote_service:
       Intent intent = new Intent("com.xf.AIDLService");
       intent.setPackage("com.xf");
       bindService(intent, reConn, BIND_AUTO_CREATE);
       break;

// Connect to remote services
   private AIDLService mAidlService;
    
    private ServiceConnection reConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //Get the IBinder object returned by the server using the asInterface() method
            //Replaced the IBinder object with the AIDLService interface object
            mAidlService = AIDLService.Stub.asInterface(iBinder);
            try {
                mAidlService.aidlService();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
    };

Test results:

From the above test results, it can be seen that the client calls the Service method of the server, that is, the client and the server communicate across processes.

Comparison between local service and remote service

  1. Divided into foreground service and background service by operation type

Front desk service

Foreground service refers to those services that are often concerned by users, so when the memory is too low, it will not be killed. The foreground service must provide a status bar notification and be placed under the "Ongoing" group. This means that this notification can only be dismissed after the service has been terminated or removed from the foreground.

example

Open foreground Service in onCreate method of Service class

@Override
    public void onCreate() {
        super.onCreate();
        System.out.println("------->onCreate");
        // Front desk service
        String channelID = "com.xf.serviceclientdemo";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelID, "Front desk service", NotificationManager.IMPORTANCE_HIGH);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
        }
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this, channelID)
                .setContentTitle("Title of the front desk service notification")
                .setContentText("Content of front desk service notice")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);//Turn the Service into the foreground Service and display it in the system status bar
    }

To remove a service from the foreground, call the stopforegroup() method, which takes Boolean parameters to indicate whether to remove the status bar notification at the same time

test result

Comparison between front service and back service

Service related knowledge

  1. When bindService() performs service binding, its flags are:
  • Context.BIND_AUTO_CREATE
    Indicates that when a binding request is received, if the service has not been created, it will be created immediately; when the system memory is insufficient, priority components need to be destroyed to free memory first, and the service will be destroyed only when the process hosting the service becomes the destroyed object.
  • Context.BIND_DEBUG_UNBIND  
    It is usually used in debugging scenarios to determine whether the bound service is correct, but it is easy to cause memory leakage, so it is not recommended to use it when it is not for debugging purposes
  • Context.BIND_NOT_FOREGROUND
    Indicates that the system will prevent the process hosting the service from having foreground priority and running only in the background
  1. Properties of the Service element:
  • android:name : service class name
  • android:label : the name of the service. If this item is not set, the default displayed service name is the class name
  • android:icon : icon for the service
  • android:permission : declare the permission of this service, which means that only the application providing the permission can control or connect to this service
  • android:process : indicates whether the service is running in another process. If this item is set, the string will be added after the package name to indicate the name of another process
  • android:enabled : if this item is set to true, the Service will be started by the system by default. If this item is not set to false by default
  • android:exported : indicates whether the service can be controlled or connected by other applications. It is not set to false by default
  1. The onStartCommand() method must return an integer. This integer describes how the system should continue to run after killing the service
  • START_STICKY

If the system kills the service after onStartCommand() returns, it will rebuild the service and call onStartCommand(), but it will not send the last intent again, instead, it will call onStartCommand() with null intent. Unless there is any intent to start the service that has not been sent, the remaining intent will continue to be sent. This applies to media players (or similar services), which do not execute commands but need to be running and on standby at all times.

  • START_NOT_STICKY

If the system kills the service after onStartCommand() returns, the service will not be rebuilt, unless there is an unsent intent. This is the safest option to avoid running a service when it is no longer required and the application can simply restart those unfinished tasks.

  • START_REDELIVER_INTENT

If the system kills the service after onStartCommand() returns, the service is rebuilt and onStartCommand() is called with the last sent intent. Any unfinished intent will be sent in turn. This applies to active services that require immediate recovery, such as downloading files.

Posted by clank on Thu, 25 Jun 2020 03:46:33 -0700