Android creates started service services

  • 2020-05-24 06:09:20
  • OfStack

Create started service

The application component (for example, Activity) calls startService() to start an Service, passing the required parameters through Intent to Service, and Service will get Intent in the onStartCommand function.

There are two ways to create started service, one that extends the Service class, and one that extends the IntentService class

Extension Service
This is the base class for all services. When extending this class, it is especially important to create a new thread to do the service task, because service runs on your main thread (UI thread) by default, which makes your main thread run slowly.

Extension IntentService
This is a subclass of service that handles all startup requests in one worker thread. If you don't need to come out with all the service requests at the same time, IntentService is a good choice. All you need to do is implement the onHandlerIntent() method, which handles every startup request accepted.


Now let's learn how to extend the IntentService class and the Service class

Extend IntentService class

What does IntentService do?
1. Create a worker thread independent of the main thread to execute all intent sent through onStartCommand().
2. Create a work queue and pass all the intent1 and 1 to onHandlerIntent(), so you can only handle 1 intent in the same time. Don't worry about multi-threading.
3. When all requests have been processed, stop the service, so you don't need to manually call stopSelf().
4. Provide the default implementation of the onBind() function, returning null
5. Provide the default implementation of the onStartCommand() function, which sends intent to the work queue, which then sends it to your onHandlerIntent() function.

With that in mind, all you have to do is implement onHandlerIntent(). And implement a little constructor.

Consider the following example:


public class HelloIntentService extends IntentService {
  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }
  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}

If you need to implement other callback functions, such as onCreate, onStartCommand,onDestroy 1, you must remember to call the corresponding functions of the parent class so that IntentService can properly handle the worker thread.

For example, if you need to pop up a prompt in the onStartCommand function, you can say:


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
}

With one exception, if you need another component binding service, your onBind function does not need to call the onBind of the parent class.

In the next section, you'll see that extending the service class implements the same service as in this section. The difference is that there is more code, but it also means more flexibility, especially if you need to process multiple requests at once.

Extend Service class

As you saw in the previous section, it is very easy to implement an started service using IntentService. If you need your service to execute multiple threads, then you need to extend the Service class to handle each intent.

For comparison, the following example USES the Service class to implement a service similar to the one in the previous section.


public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;
  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }
  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      // If we get killed, after returning from here, restart
      return START_STICKY;
  }
  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }
  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

As you can see, there's a lot more code than the IntentService example.

Because you handle onStartcommand() each time yourself, you can handle multiple requests at the same time. This example doesn't do that, but if you want, you can create a new thread every time you receive a request and run it immediately, rather than waiting until the last request has been processed.

Note that the onStartCommand() function must return an integer. This integer describes how the service will be handled when the system kills it. The return value must be the following:
START_NOT_STICKY
After onStartCommand() returns, the system kills the service and the service will not restart unless there is an pending intents to deliver. This is ideal for situations where it is very easy to restart unfinished tasks.

START_STICKY
After the system kills the service, restart the service and call onStartCommand(), but do not repost intent once. The system will pass onStartCommand() function null, unless pending intent is available to start the service, onStartCommand() corresponding intent will be passed. This works well with media-playing services, which do not need to execute commands, but run independently and are often waiting for tasks.

START_REDELIVER_INTENT
After the system kills the service, restart the service and call onStartCommand(). The parameter is passed to intent the previous time, and then pending intent is passed to onStartCommand(). This is appropriate for a job that is being performed and cannot be immediately restored, such as downloading a file.

Start the Service

You can start the service by calling startService(intent) from an Activity or other component. The Android system calls the onStartCommand() function of the service and passes it intent.

Use HelloService from section 1 for an example:
Intent intent = new Intent(this, HelloService.class);
startService(intent);
startService() returns immediately, and the Android system calls the onStartCommand() function of the service. If the service is not running, the system calls onCreate() first, then onStartCommand().

If the service does not provide a binding, then intent passed in through the startService() function is the only way for the application component to interact with the service. If you want the service to send results to the customer component, the customer component needs to create an PendingIntent for broadcasting when the service is started, and deliver it to the service via intent. This allows the service to broadcast the results to the customer component.

Multiple requests result in the service's onStartCommand() being called multiple times. However, all it takes is one stop request (stopSelf() or stopService()) to stop the service.

Stop the service

A startup service must manage its own lifecycle. Because unless the system needs to recycle resources, the system will not stop or destroy the service. Therefore, the service must either stop itself by calling stopSelf() or have another component call stopService().

If you receive a stop request from stopSelf() or stopService(), the system will destroy the service immediately.

If your service is processing multiple service requests at the same time, you cannot stop the service immediately when a request is completed, because you may have already accepted a new request (ending the service when the first request is completed will terminate the second request). To solve this problem, you can call the stopSelf(int) function to ensure that your stop request is always based on the last service request. This is because the stopSelf(int) function is called
The startId passed in from the onStartCommand() function is passed to the stop request. When your startId does not match the last service request you received, the service does not end.

Note: stopSelf (int) functions is simply compared with recent startId once received, if your service is multithreaded processing, may service requests received after finish, the stopSelf (int) program is not for you, you should accept manual management to the service request and complete service, such as in onStartCommand () function to startId records in a table, when the service task record completion status in the table, in the case of a table to ensure that tasks are completed in direct call stopSelf () to stop the service.

Run the service in the foreground

A foreground service is a service that users are clearly aware of and the system will not kill the foreground service when the available memory is low. A front desk service must provide a status bar notification in the running entry, which means that as long as the service is not stopped or 1 is a front desk service, the notification will not disappear.

For example, a music player service should be set up to run in the foreground because the user is clearly aware that it is running. This status bar notification displays the song being played and allows the user to click into the music playing interface.

To get the service running in the foreground, simply call startForeground(). This method takes two parameters: 1 notification integer ID and 1 status bar notification. Code snippet:


Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

Services can be removed from the foreground using the stopForeground() function. This function takes a Boolean parameter to indicate whether to remove the notification from the status bar. This function does not stop the service. If the front desk service is stopped, the notification will be removed at the same time.


Related articles: