Android面试-3 Service

简介

计算型组件,可以在后台执行长时间运行操作而没有用户界面的应用组件。有两启动(用于执行后台计算)和绑定(用于其他组件和Service交互)两种运行状态,

自定义Service

  • onBind: Service子类必须重写该方法。若是启动状态,则不该方法只需返回null,在绑定状态的情况下则返回一个IBinder的实现类,供客户端用来与服务进行通信。
  • onCreate: 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。如果服务已在运行,则不会调用此方法,该方法只调用一次
  • onStartCommand: 当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。(在绑定状态下,无需实现此方法。)。该方法有三个参数(intent,flag,startid)
  • onDestory: 当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。

两种状态

Android面试-3 Service

启动状态

startService开启,服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响,除非手动调用才能停止服务, 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。启动状态的生命周期:第一次调用startService方法时,onCreate方法、onStartCommand方法将依次被调用,而多次调用startService时,只有onStartCommand方法被调用,最后我们调用stopService方法停止服务时onDestory方法被回调

绑定状态

bindService开启。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。多次绑定同一个Service,onBind只会调用一次。

绑定状态实现步骤:

  • 必须提供一个 IBinder接口的实现类(扩展Binder,使用Messager,使用AIDL)
  • 在客户端创建ServiceConnection,系统会调用ServiceConnection的onServiceConnected方法以传递服务的 onBind() 方法返回的 IBinder,Service服务被意外销毁时,例如内存的资源不足时onServiceDisConnected被自动调用,注意:当客户端取消绑定时,系统“绝对不会”调用该方法。
  • 然后绑定服务用bindService(Intent service, ServiceConnection conn, int flags),多次绑定只回调一次onbind。解除绑定用unbindService(ServiceConnection conn),多次绑定只需一次解绑,即可销毁服务。通常绑定和解除绑定放在onStart/onStop或onCreate/onDestroy中,不放在onResume/onPause中,因为后者可能由于时序关系重建Service。

先绑定后启动

如果当前Service实例先以绑定状态运行,然后再以启动状态运行,那么绑定服务将会转为启动服务运行,这时如果之前绑定的宿主(Activity)被销毁了,也不会影响服务的运行,服务还是会一直运行下去,指定收到调用停止服务或者内存不足时才会销毁该服务

先启动后绑定

如果当前Service实例先以启动状态运行,然后再以绑定状态运行,当前启动服务并不会转为绑定服务,但是还是会与宿主绑定,只是即使宿主解除绑定后,服务依然按启动服务的生命周期在后台运行。在这种情况下,除非所有客户端均取消绑定,否则 stopService() 或 stopSelf() 不会真正停止服务。

前台服务

前台服务被认为是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。 前台服务必须为状态栏提供通知,状态栏位于“正在进行”标题下方,这意味着除非服务停止或从前台删除,否则不能清除通知。例如将从服务播放音乐的音乐播放器设置为在前台运行。在Service内部调用startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID,notification);

保证服务不被杀死

  • 若要防止内存紧张而杀死服务,则可将onStartCommand() 方法的返回值设为 START_STICKY或START_REDELIVER_INTENT ,该值表示服务在内存资源紧张时被杀死后,在内存资源足够时再恢复。也可将Service设置为前台服务,这样就有比较高的优先级,在内存资源紧张时也不会被杀掉
  • 若要防止用户手动杀死,即用户通过 settings -> Apps -> Running -> Stop 方式杀死Service 。这种情况是用户手动干预的,不过幸运的是这个过程会执行Service的生命周期,也就是onDestory方法会被调用,这时便可以在 onDestory() 中发送广播重新启动。这样杀死服务后会立即启动。这种方案是行得通的,但为程序更健全,我们可开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B,服务B监听A的广播来启动A

参考

https://blog.csdn.net/javazejian/article/details/52709857