One of the four major components of Android Service (service)

Introduction to Service

Service (service) is one of the four major components of Android. Its main function is to perform background operations. Activity provides a UI interface to interact with users, while Service has no UI interface, and all operations are completed in the background.

Service, like Activity, can also be started by other applications. Even if the user switches to other applications, Service remains running in the background.

In addition, a component can be bound to the Service to interact with the Service, and even perform inter-process communication (IPC).

Usually, Service can be used for network request, music playback, file I/O and other operations.

When creating a Service, you must inherit the Service, and you need to override some methods of the parent class to realize the function. The following is an introduction to the main methods.

Service introduction system method onCreate() onStartCommand() onBind() onUnbind() onDestroy() life cycle startService() bindService() In the Service life cycle, the commonly used methods are: create service start service startService() bindService system resource recovery IntentService foreground service What is foreground service? Why use a foreground service? How to create a foreground service? The difference between foreground service and ordinary serviceService keep aliveImprove the priority of ServicePersistent attributeChange service to foreground serviceReference materials

systematic approach

onCreate()

The system will call this method to initialize some one-time variables when starting the Service for the first time. If the Service has already started, this method will not be called again.

onStartCommand()

The system calls this method when another component (eg Activity) starts the Service startService()by . Once this method is executed, the Service starts and executes indefinitely in the background.

If this method is implemented, after the Service is executed, stopSelf() or stopService() needs to be called to stop and end the Service.

If you only start the Service by binding (bind), you don't need to override this method.

onBind()

The system will call this function when a component (eg activity, fragment) starts the Service by calling the bindService()binding . When implementing this function, an IBinder inheritance class must be returned to communicate with the Service.

This function must be rewritten by default, but if you don't want to start the Service through binding, you can return it directly null.

onUnbind()

The system calls this method when another component unbinds from the service by calling unbindService().

onDestroy()

The system will call this method when the Service is no longer needed and ready to be destroyed. If threads, listeners, receivers, etc. are used in Service, these cleaning methods should be written in this method.

life cycle

startService()

onCreate() -> onStartCommand() -> onDestroy()

bindService()

onCreate() -> onBind() -> onUnbind() -> onDestroy()

In the life cycle of Service, the commonly used methods are:

  • Method called manually:

Manually call the method effect
startService() start service
stopService() close service
bindService() Binding service
unbindService() unbundling service
  • The method called automatically:

Automatic method call effect
onCreat() create service
onStartCommand() start service
onDestroy() destruction service
onBind() Binding service
onUnbind() unbundling service

create service

To create a Service, you first need to inherit Service to implement a subclass.

public class TestService extends Service {
​
  @Override
  public void onCreate() {
    super.onCreate();
  }
​
  @Override
  public int onStartCommand(Intent intent, int flags,
                            int startId) {
    return super.onStartCommand(intent, flags, startId);
  }
​
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }
​
  @Override
  public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
  }
​
  @Override
  public void onDestroy() {
    super.onDestroy();
  }
}

Similar to Activity, all Services must be declared in the Manifest, as follows:

<manifest ... >
  ...
  <application ... >
    <service android:name="xxx.xxxs.TestService" />
    ...
  </application>
</manifest>

<service>By android:exportedsetting in the tag to false. Can prevent other programs from starting your Service.

start service

Usually there are two ways to start the Service, startService()and bindService().

startService()

The life cycle of stratService:

onCreate() -> onStartCommand() -> onDestroy()

insert image description here

Intent intent = new Intent(this, TestService.class); 
startService(intent); // start service 
stopService(intent); // stop service

After the component startService()starts , the Service can run indefinitely in the background, even if the component that started the Service is destroyed, it will not be affected.

In general, a single operation startService()is performed, and the execution result is not returned to the caller. For example, it might be downloading a file or uploading a file, usually it stops automatically when the operation is complete.

This method allows multiple components to startService()operate , but if only one of the components calls stopSelf()or stopService(), the Service will be destroyed.

bindService

The life cycle of bindService:

onCreate() -> onBind() -> onUnbind() -> onDestroy()

insert image description here

Intent intent = new Intent(this, TestService.class);
ServiceConnection connection = new ServiceConnection() {
  @Override
  public void onServiceConnected(ComponentName name, 
                                 IBinder service) {
  }
​
  @Override
  public void onServiceDisconnected(ComponentName name) {
  }
};
// 绑定服务
bindService(intent, connection, Context.BIND_AUTO_CREATE);
// 解绑服务
unbindService(aidlConnection);

When the component bindService()starts , the Service is in the bound state. This method provides a client-service interface, allowing the caller to send requests and return results with the Service, and even perform inter-process communication (IPC).

As long as there is a component bound to the Service, the Service will not be destroyed. If multiple components can bind a Service at the same time, the Service will be destroyed only after all the bound components of the Service are unbound.

Although the two methods are discussed separately, they are not mutually exclusive. After the Service is startService()started , it can also be bound.

Note: Although the Service is running in the background, all operations are actually performed in the main thread. When the Service starts, unless it is defined separately, the thread is not opened separately or the process is running in the main thread.

Therefore, any operation that can block the main thread (such as playing music or network requests) should open a new thread in the Service for operation, otherwise ANR will easily occur.

System Resource Recycling

When the system memory is insufficient, the system will forcibly recycle some Activities and Services to obtain more resources for the programs or pages that the user is interacting with. When the resources are sufficient, the return value onStartCommand()of to realize the automatic restart of the Service.

public int onStartCommand(Intent intent, int flags, int startId) {
  return START_NOT_STICKY | START_STICKY | START_REDELIVER_INTENT;
}
name meaning
START_NOT_STICKY When the system destroys the Service due to reclaiming resources, the Service will not be automatically started when the resources are sufficient again, unless there is an unprocessed Intent ready to be sent.
START_STICKY When the system destroys the Service due to recycling resources, it will automatically start the Service when the resources are sufficient again. And onStartCommand()the method , but the last Intent will not be delivered. On the contrary, the system onStartCommand()will pass an empty Intent when calling back, unless there is an unprocessed Intent ready to be sent.
START_REDELIVER_INTENT When the system destroys the Service due to reclaiming resources, it will automatically start the Service when the resources are sufficient again, and call onStartCommand()the method , and will pass the last Intent to the service again onStartCommand(), and the corresponding Intents in the queue will also be delivered in order. This mode is suitable for services such as downloads.

IntentService

The Service itself runs in the main thread by default, so if you want to perform some operations that will block the thread in the Service, you must put these operations in a new thread. In order to meet the needs of running asynchronous threads in the background, the Android framework provides IntentService.

IntentService is a subclass of Service, and all request operations are performed in an asynchronous thread. If you need Service to handle multiple requests at the same time, IntentService will be the best choice.

To use this service, you only need to inherit and rewrite onHandleIntent()the method , and then you can Intentperform background asynchronous thread operations on the received .

public class TestIntentService extends IntentService {
​
  public TestIntentService() {
    super("TestIntentService");
  }
​
  public TestIntentService(String name) {
    super(name);
  }
​
  @Override
  public void onCreate() {
    super.onCreate();
  }
​
  @Override
  protected void onHandleIntent(@Nullable Intent intent) {
    //TODO: 耗时操作,运行在子线程中
  }
​
  @Override
  public void onDestroy() {
    super.onDestroy();
  }
}

Reception

What is a foreground service?

Foreground services are those that are considered user-aware (user-approved) and are not allowed to be killed by the system when the system runs out of memory.

Foreground services must provide a notification in the status bar, which is placed under the Ongoing heading - this means that the notification can only be dismissed after the service is terminated or the notification is actively removed from the foreground.

Why use a foreground service?

Under normal circumstances, Service is almost always running in the background, doing hard work silently. But in this case, the service system running in the background has a relatively low priority. When the system memory is insufficient, the service running in the background may be recycled.

Then, if we want the Service to keep running and not be recycled in the event of insufficient memory, we can choose to set the Service that needs to keep running as a foreground service.

For example: the music playback service in the app should be set to run in the foreground (foreground service) - when the app is running in the background, it is convenient for the user to clearly know its current operation, indicate the current song information in the status bar, and provide corresponding operations.

How to create a foreground service?

public class ForegroundService extends Service {
  
  private static final int RESULT_CODE = 0;
  private static final int ID = 1;
  
  public ForegroundService() { }

  @Override
  public void onCreate() {
    super.onCreate();
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, RESULT_CODE, 
                              intent, PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationCompat.Builder builder;
    // 兼容 Android 8.0
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      String channelId = "foreground_service";
      NotificationChannel channel = new NotificationChannel(channelId, 
                              "channel_1", NotificationManager.IMPORTANCE_HIGH);
      channel.enableLights(true);
      channel.setLightColor(Color.GREEN);
      channel.setShowBadge(true);
      NotificationManager notificationManager = 
        											getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(channel);
      builder = new NotificationCompat.Builder(this, channelId);
    } else {
      builder = new NotificationCompat.Builder(this);
    }
    builder.setContentIntent(pendingIntent)
      .setContentTitle("这是前台通知标题")
      .setContentText("这是内容")
      .setWhen(System.currentTimeMillis())
      .setSmallIcon(R.mipmap.ic_launcher_round)
      .setLargeIcon(BitmapFactory.decodeResource(getResources(), 
                                                 R.mipmap.ic_launcher))
      .setPriority(NotificationManager.IMPORTANCE_HIGH)
      .setDefaults(Notification.DEFAULT_SOUND);

    startForeground(ID, builder.build());
  }
  
  @Override
  public int onStartCommand(Intent intent, int flags,
                            int startId) {
    return super.onStartCommand(intent, flags, startId);
  }

  @Override
  public IBinder onBind(Intent intent) {
    return super.onBind(intent);
  }
}

Start and stop foreground services

Intent foregroundIntent = new Intent(this, ForegroundService.class); 
startService(foregroundIntent); // Start the foreground service 
stopService(foregroundIntent); // Stop the foreground service

The difference between front desk service and normal service

  • The system priority of the foreground Service is higher and it is not easy to be recycled;

  • Foreground Service will always have a running icon displayed in the status bar of the system. After pulling down the status bar, you can see more detailed information, which is very similar to the effect of notification.

service keep alive

Through the previous introduction, we learned that Service is a background service to perform some specific tasks, but when the background service is insufficient in system resources, it may recycle and destroy the Service.

So how to keep the background service from being killed as much as possible? The basic solution is as follows:

Increase the priority of Service

In order to prevent the Service from being recycled by the system, you can try to solve it by increasing the priority of the service. The highest priority value is 1000, and the smaller the number, the lower the priority.

<service android:name=".ui.service.TestService" >
  <intent-filter android:priority="1000"/>
</service>

persistent attribute

Setting the persistent attribute to true in the Manifest.xml file makes the service immune to out-of-memory killers. But this approach must be cautious, too many system services will seriously affect the overall operating efficiency of the system.

<application android:persistent="true">
</application>

The characteristics of this property are as follows:

  • It will be activated by the system when the system starts.

  • After the app is forcibly killed, the system will restart the app. This is only for the built-in app in the system, and the third-party installed app will not be restarted.

Change the service to a foreground service

Override the onStartCommand method and use startForeground(int, Notification)the method to start the Service. Using Android's system broadcast

Use the Android system broadcast to check the running status of the Service, and restart it if it is killed. The system broadcast is Intent.ACTION_TIME_TICK, this broadcast is sent once every minute. We can check the running status of the Service every minute, and restart the Service if it has been destroyed.

References

Guess you like

Origin blog.csdn.net/fry3309/article/details/125281178