Comprehensive analysis of Android components Service

Preface

Service (Service) is a solution to realize the background operation of the program in Android, which is very suitable for performing long-running tasks that do not require interaction with the user .

Key points

  • Depends on the application process in which the service is created, not running in a separate process.
  • Time-consuming operations need to manually create child threads within the service and perform specific tasks here, otherwise the main thread may be blocked.

life cycle

life cycle
Service has three ways to start the service:

  • Start the service : startService() opens the service, stopService() closes the service

startService() callback onCreate ——> onStartCommand
stopService() callback onDestroy

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

bindService() callback onCreate ——> onBind
unbindService() callback onUnBind——>onDestory

  • Hybrid method : start the service first, then bind the service

startService() callback onCreate ——> onStartCommand; bindService() callback onBind, unbindService() callback onUnBind; stopService() callback onDestroy

Key points :

  • No matter how many times the service is opened, the onCreate method will only be called once, and the system will only create one instance of the Service
  • In the entire 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 binds the service and can also operate the service

Service classification

  1. Divided by operating location : local service and remote service

Local service

Used in the application program to implement some time-consuming tasks, the most common and commonly used background service Service.

Instance

MyService class

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

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

    @Override
    public void onDestroy() {
    
    
        super.onDestroy();
        System.out.println("执行了onDestory()");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    
    
        return mBinder;
    }
    
    private MyBinder mBinder = new MyBinder();
    class MyBinder extends Binder {
    
    
        public String printServiceInfo() {
    
    
            return "Activity 和 Service 建立通信,传递数据";
        }
    }
}

Construct the Intent object in Activity, and call startService() to start the Service, stopService to stop the service, bindService to bind the service, unbindService to unbind the 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;

    //创建ServiceConnection的匿名类
    private ServiceConnection connection = new ServiceConnection() {
    
    
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    
    
            //实例化Service的内部类myBinder
            //通过向下转型得到了MyBinder的实例,Binder实现了IBinder 接口
            myBinder = (MyService.MyBinder) iBinder;
            //在Activity调用Service类的方法
            String info = myBinder.printServiceInfo();
            System.out.println("---------->" + info);
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
    
    
        }
    };

Register Service in AndroidManifest.xml

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

The result of the operation is
test

Remote Service

It is used between applications within the Android system and can be reused by other applications, such as weather forecast services. Other applications do not need to write such services, just call the existing ones. Interfaces can be defined and exposed for other applications to operate. 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 methods defined in AIDL in the Service subclass, and define life cycle methods
  • Register the service in AndroidMainfest.xml and declare it as a remote service
Server-side instance

Create a new AIDL file, define the content (method) that Service needs to communicate with Activity in the new AIDL file, and compile it (Make Project)
Insert picture description here

interface AIDLService {
    
    
    /**
     * //AIDL中支持以下的数据类型
       //1. 基本数据类型
       //2. String 和CharSequence
       //3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型;
       //4. AIDL自动生成的接口(需要导入-import)
       //5. 实现android.os.Parcelable 接口的类(需要导入-import)
     */
    void aidlService();
}

Compile
Implement the interface methods defined in AIDL in the Service subclass, and define life cycle methods

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("客户端通过AIDL与远程后台成功通信");
        }
    };
}

Register the service in AndroidMainfest.xml & declare it as a remote service

        <service
            android:name=".service.ServiceDemo"
            android:exported="true" //设置可被其他进程调用
            android:process=":remote">//将本地服务设置成远程服务
            <intent-filter>
                 // 此处Intent的action必须写成“服务器端包名.aidl文件名”
                <action android:name="com.xf.AIDLService"/>
            </intent-filter>
        </service>

Client :

  • Copy the AIDL file of the server to the directory
  • Use the Stub.asInterface interface to obtain the Binder of the server, and call the interface methods provided by the service as needed
  • Specify the service name and package of the server through the Intent, and bind the remote Service
Client instance

Copy the package where the AIDL file of the server is located to the client directory (Project/app/src/main), and compile it
aidl
in the Activity, use the Stub.asInterface interface to obtain the Binder of the server; specify the service name and location of the server through the Intent Package, perform Service binding; call the interface methods provided by the service as needed.

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

// 连接 远程服务
   private AIDLService mAidlService;
    
    private ServiceConnection reConn = new ServiceConnection() {
    
    
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    
    
            //使用asInterface()方法获取服务器端返回的IBinder对象
            //将IBinder对象传换成了AIDLService接口对象
            mAidlService = AIDLService.Stub.asInterface(iBinder);
            try {
    
    
                mAidlService.aidlService();
            } catch (RemoteException e) {
    
    
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
    
    
        }
    };

Test results :
Insert picture description here
As can be seen from the above test results, the client has called the method of the server Service, that is, the client and the server have carried out cross-process communication .

Comparison of local service and remote service

Insert picture description here

  1. Divided into foreground service and background service according to operation type

Reception

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

Instance

Open the foreground service in the onCreate method of the Service class

@Override
    public void onCreate() {
    
    
        super.onCreate();
        System.out.println("------->onCreate");
        // 前台服务
        String channelID = "com.xf.serviceclientdemo";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
            NotificationChannel channel = new NotificationChannel(channelID, "前台服务", 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("前台服务通知的标题")
                .setContentText("前台服务通知的内容")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来
    }

To remove the service from the foreground, call the stopForeground() method. This method accepts a boolean parameter that indicates whether to remove the status bar notification at the same time

Test Results
ss

Front-end service and back-end service comparison

Insert picture description here

Service related knowledge

  1. When bindService() performs service binding, its flags are :
  • Context.BIND_AUTO_CREATE
    means that when the 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 first to release the memory, and only the process that resides in the service becomes the destroyed object, the service Was destroyed.
  • Context.BIND_DEBUG_UNBIND  
    is usually used in debugging scenarios to determine whether the bound service is correct, but it is easy to cause memory leaks, so it is not recommended to use it for non-debugging purposes
  • Context.BIND_NOT_FOREGROUND
    indicates that the system will prevent the process that resides in the service from having foreground priority and only run in the background
  1. The attributes of the Service element :
  • android:name: service class name
  • android:label: the name of the service, if this item is not set, the service name displayed by default is the class name
  • android:icon: the icon of the service
  • android:permission: Affirm the permission of this service, which means that only applications that provide this permission can control or connect to this service
  • android:process: Indicates whether the service is running in another process. If this is set, this string will be added to the package name to indicate the name of another process
  • android:enabled: If this item is set to true, then the Service will be started by the system by default, and the default item is false if it is not set
  • android:exported: Indicates whether the service can be controlled or connected by other applications. If it is not set, the default item is false
  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 will not send the previous intent again, but call onStartCommand() with a null intent. Unless there are still intents that start the service that have not been sent, the remaining intents 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, it will not rebuild the service, unless there are still unsent intents. When the service is no longer necessary, and the application can simply restart the unfinished work, this is the safest option to avoid running the service.

  • START_REDELIVER_INTENT

If the system kills the service after onStartCommand() returns, it will rebuild the service and call onStartCommand() with the last sent intent. Any unsent intents will also be sent in order. This applies to active services that need to resume work immediately, such as downloading files.

Guess you like

Origin blog.csdn.net/xufei5789651/article/details/106939548