安卓service

与前一篇Android之Activity的细枝末节是同一系列的文章,是自己在学习和研发过程中,对Service的一些知识点的总结,汇总得到这篇文章。

这篇文章会从Service的一些小知识点,延伸到Android中几种常用进程间通信方法。

  1. 进程
    Service是一种不提供用户交互页面但是可以在后台长时间运行的组件,可以通过在AndroidManifest.xml设置Service的android:process=":remote"属性,让Service运行另一个进程中,也就是说,虽然你是在当前应用启动的这个Service,但是这个Service和这个应用并不是同一个进程。

四大组件都支持android:process=":remote"这个属性。

因为Service可以运行在不同的进程,这里说一下Android中几种进程的优先级,当系统内存不足时候,系统会从优先级低的进程开始回收,下面根据优先级由高到低列出Android中几种进程。

前台进程,当前用户操作所需要的进程

用户正在交互的Activity(Activity执行了onResume方法)
与正在交互的Activity绑定的Service
设置为前台权限的Service(Service调用startForeground()方法)
正在执行某些生命周期回调的Service,onCreate()、onStart()、onDestroy()
正在执行onReceive()的BroadcastReceiver
这种进程基本不会被回收,只有当内存不足以支持前台进程同时运行时候,系统才回回收它们,主要关注前三个。

可见进程,没有与用户交互所必须的组件,但是在屏幕上仍然可见其内容的进程

调用了onPause()方法但仍对用户可见的Activity
与上面这种Activity绑定的Service
服务进程,使用startService()启动的Service且不属于上面两种类别进程的进程,虽然这个进程与用户交互没有直接关系,但是一般会在后台执行一些耗时操作,所以,只有当内存不足以维持所有前台进程和可见进程同时运行,系统才回回收这个类别的进程。

后台进程,对用户不可见的Activity进程,已调用了onStop()方法的Activity

空进程,不包含任何活动应用组件的进程,保留这种进程唯一目的是作为缓存,缩短引用组件下次启动时间。通常系统会最优先回收这类进程。
此外,一个进程的级别可能会因为其他进程对它的依赖而有所提高,即进程A服务于进程B(B依赖A),那么A的进程级别至少是和B一样高的。

  1. Service配置
    和其他组件(Activity/ContentProvider/BroadcastReceiver)一样,Service需要在Androidmanifest.xml中声明。

<manifest ... >
...
<application ... >

...


1
2
3
4
5
6
7
Service是运行在主线程中的,如果有什么耗时的操作,建议新建子线程去处理,避免阻塞主线程,降低ANR的风险。

   在另外一篇文章中Intent以及IntentFilter详解提到过,为了确保应用的安全,不要为Service设置intent-filter,因为如果使用隐式Intent去启动Service时候,手机里面那么多应用,并不能确定哪一个Service响应了这个Intent,所以在项目中尽量使用显式Intent去启动Service。在Android 5.0(API LEVEL 21)版本后的,如果传入隐式Intent去调用bindService()方法,系统会抛出异常。

可以通过设置android:exported=false来确保这个Service仅能在本应用中使用。

  1. 服务启动方式
    服务可以由其他组件启动,而且如果用户切换到其他应用,这个服务可能会继续在后台执行。到目前为止,Android中Service总共有三种启动方式。

Scheduled,可定时执行的Service,是Android 5.0(API LEVEL 21)版本中新添加的一个Service,名为JobService,继承Service类,使用JobScheduler类调度它并且设置JobService运行的一些配置。具体文档可以参考JobScheduler,如果你的应用最低支持版本是21,官方建议使用JobService。
Started,通过startService()启动的Service。通过这种方式启动的Service会独立的运行在后台,即使启动它的组件已经销毁了。例如Activity A使用startService()启动了Service B,过了会儿,Activity A执行onDestroy()被销毁了,如果Service B任务没有执行完毕,它仍然会在后台执行。这种启动方式启动的Service需要主动调用StopService()停止服务。
Bound,通过bindService()启动的Service。通过这种方式启动Service时候,会返回一个客户端交互接口,用户可以通过这个接口与服务进行交互,如果这个服务是在另一个进程中,那么就实现了进程间通信,也就是Messenger和AIDL,这个会是下篇文章的重点。多个组件可以同时绑定同一个Service,如果所有的组件都调用unbindService()解绑后,Service会被销毁。
startService和bindService可以同时使用

  1. 主要方法
    Service是一个抽象类,使用需要我们去实现它的抽象方法onBind(),Service有且仅有这一个抽象方法,还有一些其他的生命周期回调方法需要复写帮助我们实现具体的功能。

onCreate(),在创建服务时候,可以在这个方法中执行一些的初始化操作,它在onStartCommand()和onBind()之前被调用。如果服务已经存在,调用startService()启动服务时候这个方法不会调用,只会调用onStartCommand()方法。
onStartCommand(),其他组件通过startService()启动服务时候会回调这个方法,这个方法执行后,服务会启动被在后台运行,需要调用stopSelf()或者stopService()停止服务。
onBind(),其他组件通过bindService()绑定服务时候会回调的方法,这是Service的一个抽象方法,如果客户端需要与服务交互,需要在这个方法中返回一个IBinder实现类实例化对象,如果不想其他客户端与服务绑定,直接返回null。
onDestroy(),当服务不在还是用且即将被销毁时,会回调这个方法,可以在这个方法中做一些释放资源操作,这是服务生命周期的最后一个回调。
如果组件仅通过startService()启动服务,不论服务是否已经启动,都会回调onStartCommand()方法,而且服务会一直运行,需要调用stopSelf和stopService方法关闭服务。

如果组件仅通过bindService()绑定服务,则服务只有在与组件绑定时候运行,一旦所有的客户端全部取消绑定unbindService,系统才会销毁该服务。

多次启动同一个服务,只有在服务初次启动时候会回调onCreate方法,但是每次都会回调onStartCommand,可以利用这个向服务传递一些信息。

onStartCommand()的回调是在UI主线程,如果有什么耗时的操作,建议新启线程去处理。

  1. 启动和关闭服务
    启动服务:

JobScheduler.schedule()
startService(Intent)
bindService(Intent service, ServiceConnection conn, int flags)
关闭服务:

JobScheduler.cancel()或者JobScheduler.cancelAll(),对应JobScheduler.schedule()
Service自身的stopSelf()方法,组件的stopService(Intent)方法,对应startService启动方法
unbindService(ServiceConnection conn),对应bindService

posted @ 2020-11-07 10:40  软工卓越  阅读(60)  评论(0编辑  收藏  举报