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
- 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
- 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
- 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
- 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
- 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.