Android服务(Service)

一、介绍

Service是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。

二、3种服务

服务分为三种:前台服务、后台服务、绑定服务

【1】前台服务

前台服务执行一些用户能注意到的操作。
例如,音频应用会使用前台服务来播放音频曲目。
前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。

【2】后台服务

后台服务执行用户不会直接注意到的操作。
例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。

【3】绑定服务

当应用组件通过调用 bindService() 绑定到服务时,服务即处于绑定状态。
绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,
甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。
多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
三、注册服务

Service需要在清单文件中声明:


    
        
    

ExampleService 是 Service 的子类:

public class ExampleService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
}
四、启动服务和停止服务

通过 startService 启动服务:

            // 必须显示启动services
            Intent intent = new Intent(MainActivity.this, ExampleService.class);
            startService(intent);

Intent 必须是显式,否则程序将会报错。

另外,还有一种启动方式,启动前台服务:

startForegroundService() // Android 8.0新增

Android 8.0(API 26)对Service做了一些限制,因为某些限制,新增了 startForegroundService 接口。

API 26 之后,当在前台启动Service时,startService 和 startForegroundService 并没有什么区别。当在后台启动Service时,则必须使用 startForegroundService 接口,将 Service 从后台切换到前台,并且在5秒之内调用自己的 startForeground() 方法。

通过 stopService 可以停止服务:

            Intent intent = new Intent(MainActivity.this, ExampleService.class);
            stopService(intent);

当然,也可以在服务结束的地方执行 stopSelf() 来停止服务。

启动服务之后,服务将在内存中一直运行,直到执行 stopService 或者 stopSelf 停止服务。

五、IntentService

onStartCommand 方法中不能存在耗时操作,否则主线程会被阻塞,甚至可能导致发生crash和ANR。
即使 onStartCommand 执行的不是耗时操作,当多次启动服务,onStartCommand 会被执行多次,这种情况仍然可能导致程序异常或者ANR。
为了保守起见,onStartCommand 的工作应该另起一个线程执行,除非能够保证没有耗时操作。

IntentService 会创建一个作业线程来执行任务,并且还可以保证线程安全,所以可以把 IntentService 做为 Service 的替代方案。

IntentService同样需要在注册:


    
        
    


public class HelloIntentService extends IntentService {

    public HelloIntentService() {
        super("HelloIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
    }
}

启动IntentService:

            Intent intent = new Intent(MainActivity.this, HelloIntentService.class);
            startService(intent);

启动IntentService会执行以下操作:

  • 创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。
  • 创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样您就永远不必担心多线程问题。
  • 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。
  • 提供 onBind() 的默认实现(返回 null)。
  • 提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现。

IntentService的业务逻辑是在 onHandleIntent 方法中执行的,onHandleIntent 方法执行在工作线程,并且能够保证线程安全,这就是 IntentService 的强大之处了。
IntentService 会自动调用 stopSelf() ,所以不需要主动调用 stopService 或者 stopSelf。但是,因为这个特性,IntentService无法保证让 Service 一直处理Running状态。

六、绑定服务

使用 bindService 绑定服务:

Intent intent = new Intent(MainActivity.this, ExampleService.class);
bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);

private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        binder = IExampleBinder.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        binder = null;
    }
};

绑定服务后,Service 会自动启动。

解绑服务:

unbindService(serviceConnection);

onBind的返回值不能为null:

public class ExampleService extends Service {

    private class MyBinder extends IExampleBinder.Stub {
        @Override
        public String getName() throws RemoteException {
            return "zhangsan";
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("ExampleService", "==onBind==");
        return new MyBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("ExampleService", "==onStartCommand1==");
        return super.onStartCommand(intent, flags, startId);
    }
}

IExampleBinder 是AIDL文件(IExampleBinder.aidl):

interface IExampleBinder {
    String getName();
}
七、新特性

Android 8 之前, 只要调用 startService 就可以启动前台服务和后台服务。

但是,在Android 8.0之后,如果当前程序在后台,就必须启动前台服务 startForegroundService:

startForegroundService(new Intent(getApplicationContext(), RemoteService.class));

启动前台服务之后,必须在5秒之内执行 startForeground 方法:

NotificationChannel channel = new NotificationChannel("persident", "persident", 
NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, "persident")
            .setAutoCancel(true)
            .setCategory(Notification.CATEGORY_SERVICE)
            .setOngoing(true)
            .setPriority(NotificationManager.IMPORTANCE_LOW).build();
        startForeground(10, notification);

startForeground 的 ID 不能为0。

如要从前台移除服务,请调用 stopForeground()。

Android 9 之后,还需要添加权限:


[本章完...]

你可能感兴趣的:(Android服务(Service))