I. Introduction to Service

A Service is one of the four components of Android. Like an Activity, it is a subclass of Context, but it does not have an interface. A Service is ideal for performing tasks that run for a long time and do not require interaction with the user. Since the Service itself is run on the main thread, if you need to perform time-consuming operations, you need to start another child thread. Otherwise, ANR errors will occur.

There are three types of services:

  • Foreground: Foreground service. Use notifications when starting to inform the user that the service is being executed. Note that the Service is still running in the background.
  • Background: Background services. Execution is imperceptible to the user.
  • Bound: binds services. When a Service is started with the bindService() method, it is a bound Service. The Service can then interact with the components it is bound to. Multiple components can be bound, and the Service is destroyed only when all bound components unbind it.

The life cycle of a Service

There are two ways to start a Service, startService() and bindService().

  • The life cycle of startService() is shown on the left in the figure above. In particular, the onStartCommand() method is called back

    • OnCreate () is called only once in the entire life cycle
    • OnStartCommand () may be called multiple times, including Service restart and repeated calls to startService()
    • StartService () stops a Service by calling its own stopSelf() method or another component calling stopService(Intent name). The name argument can be a new one, as long as the associated class is the target Service to stop.
    • StopSelf () also has an overloaded method stopSelf(int startId) that stops the request for startId alone. StartId is the parameter startId passed in by the onStartCommand() method to distinguish each access request.
  • The bindService() startup lifecycle is shown on the right in the figure above. In particular, onBind() and onUnbind() are called

    • OnCreate () is called only once in the entire life cycle
    • The same component can be bound more than once
    • OnBind () is called only on the first binding when multiple components bind to the service.
    • It is not valid for a Service started this way to stop the Service using service.stopself () or by calling stopService() on the component
    • This service runs until all the bound components call unbindService() to unbind it, and the service does not stop as long as one of the bound components is unbound.

The onStartCommand() method returns an integer value that tells the system what to do with the Service if the system kills it

  • START_NOT_STICKY: Service The server will not restart after being killed by the system
  • START_STICKY: The Service restarts after it is killed by the system. In this case, the value of the Intent passed in by onStartCommand() is null
  • START_REDELIVER_INTENT: Service restarts after it is killed by the system. In this case, the Intent value passed in by calling onStartCommand() is the Intent value passed in when startService() was last called.

Create a service

1. Create background service (no interaction)

StartService () is used to start non-interactive background services.

public class MyService extends Service{
    public static final String TAG = "MyService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG,"onBind");
        return null;
    }

    @Override
    public void onCreate(a) {
        Log.e(TAG,"onCreate");
        super.onCreate();
        runAfterStop();
    }

    private void runAfterStop(a){
        new Thread(){
            @Override
            public void run(a) {
                try {
                    Thread.sleep(5000);
                    Log.e(TAG,"stopSelf()");
                    stopSelf();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG,"onStartCommand");
        return START_NOT_STICKY;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG,"onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy(a) {
        Log.e(TAG,"onDestroy");
        super.onDestroy(); }}Copy the code

Start the service

public class BaseActivity extends AppCompatActivity{... Intent intent =new Intent(this, MyService.class); startService(intent); . }Copy the code

2. Create a front desk service

The foreground Service is displayed in the notification bar/status bar, and the Service has a higher priority.

public class ForegroundService extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate(a) {
        // ID cannot be 0, otherwise the notification/status bar will not display
        int id = 1;
        startForeground(id,createNotification());
    }

    private Notification createNotification(a){
        Intent notifiIntent = new Intent(this, FirstActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this.0,notifiIntent,0);

        Notification.Builder builder = new Notification.Builder(this)
                .setContentTitle("title")
                .setContentText("Content")
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(pendingIntent);

        returnbuilder.build(); }}...// Start the service
public class BaseActivity extends AppCompatActivity{... Intent intent =new Intent(this, MyService.class); startService(intent); . }Copy the code

To cancel foreground service, call stopForeground(Boolean removeNotification),

RemoveNotification: true indicates that the foreground service notification is canceled and the ICONS in the notification/status bar are removed. False indicates that the foreground service notification is not removed

Calling this method does not cause the service to stop, but simply rolls the foreground to the background

Notifications/status ICONS are removed when the service stops

Create a binding service (interactive)

Bound Services are in client-server mode. Because interaction is required, there is an intermediate proxy object created by the server and returned to the client as Binder, returned by onBind().

Server code:

public class BoundService extends Service {

    private IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder{
        public int add(int a,int b){
            return BoundService.this.add(a,b); }}@Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private int add(int a,int b){
        returna + b; }}Copy the code

Client code:

public class BoundActivity extends Activity{
    // Hold the Binder objects returned by the binding service
    private BoundService.LocalBinder mBinder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        serviceBind();
    }

    @Override
    protected void onStop(a) {
        super.onStop();
        unbindService(mServiceConn );
    }

    // Bind the service
    private void serviceBind(a) {
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    }

    // Click the event
    public void addClick(View view){
        add(2.3);
    }

    // Call the method to bind the service
    private void add(int a,int b){
        Log.(TAG,mBinder.add(a,b));
    }

    // The callback interface after binding the service
    private ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG,"bing Service Connected");
            mBinder = (BoundService.LocalBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG,"unBind Service disConnected");
            mBinder = null; }}; }Copy the code

This is based on the same simple in-process call. If you add process=”:remote” to BoundService in the Manifest file, the above code will report an error. Throw a Java. Lang. ClassCastException, because such a case the returned object is Binder agent BInderProxy, so throw type conversion error. Interprocess communication uses AIDL, which will be reviewed in another article.

4, IntentService

IntentService is a subclass of Service that handles asynchronous request features: A default worker thread is created to handle all intents. A queue is created to handle all intents one by one and implemented in onHandleIntent(). OnBind (); onStartCommand(); onStartCommand()

So we don’t need to manage the IntentService lifecycle and manage threads. And IntentService shuts down automatically after all tasks are processed. When the business does not need to involve multithreading, IntentService can meet most of the requirements.

To implement IntentService, simply provide a constructor and implement the onHandleIntent() method

public class TestIntentService extends IntentService {
    publicTestIntentService() {
        super("TestIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // Simulate time-consuming operations
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) { Thread.currentThread().interrupt(); }}}Copy the code

IntentService is implemented using HandlerThread + Handler. HandlerThread is a subclass of Thread. The Handler runs in the HandlerThread and processes time-consuming operations.

Services and threads threads

A Service is an Android mechanism that runs in the main thread. If a time-consuming operation is performed, a child thread needs to be created to execute it.

A Service takes precedence over a suspended Activity in the background and the child threads it creates, Thread. When running out of memory, the system may kill suspended activities or threads in the background first, rather than services.

A Thread runs independently of an Activity. When an Activity finishes, it will continue executing if the Thread is not stopped or the task is not finished. The application will no longer hold a reference to the Thread and will not be able to control it.

So when you need to run a task in the background for a long time, you need to use a Service, and when a Service needs to handle time-consuming operations while running the task, you need to create a child thread to execute them.