原创 Android之Service 介绍

2021-9-27 13:24 1161 12 12 分类: 软件与OS 文集: android studio

Service(服务)是一个没有用户界面、在后台运行、执行耗时操作的应用组件。其他应组件能够启动Service,并且当用户切换到其他应用场景时,Service 将持续在后台运行。另外,一个组件能够绑定到一个Service与之交互(IPC机制),例如,一个 Service 可能会处理网络操作、播放音乐、操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行的。

 

Service 的分类

Service可以通过运行地点和运行类型两种方式来进行分类。按运行地点分类,可以分为本地服务和远程服务两类。

本地服务(Local)

优点:该服务依附在主进程上,而不是独立的进程,在一定程度上节约了资源,另外 Local 服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应bindService 会方便很多

缺点主进程 Kill 后,服务便会终止

应用:常见的应用如酷我音乐播放服务

远程服务(Remote

优点:服务为独立的进程,对应进程名格式为所在包名加上所指定的android∶process字符串。由于是独立的进程,因此在 Activity 所在进程被Kill 的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务,具有较高的灵活性

缺点:该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。

应用:一些提供系统服务的Service,这种 Service 是常驻的

在实际的开发实践中,Remote Service 相对是很少见的,并且一般都是系统服务,所以本章讲解的重点是 Local Service

 

按运行类型分类,Service也可以分为两类。

前台服务与后台服务

前台服务

前台服务会在通知一栏显示 ONGOING Notification

当服务被终止的时候,通知一栏的 Notification 也会消失,对于用户有一定的通知作用,常见的如音乐播放服务

后台服务

默认的服务即为后台服务,即不会在通知一栏显示 Notification

当服务被终止的时候,用户是看不到效果的,包括一些不需要运行或终止提示的服务,如天气更新、日期同步、邮件同步等

有的读者可能会问,后台服务可不可以通过自己创建的 Notification

关于Notification知识会在后面进行讲解,此处知道即可)来成为前台服务?答案是否定的,前台服务在做了上述工作之后,再调用 startForeground()Andrid 2.0 及其以后版本)或setForeground()Android2.0 以前的版本)。这样做的好处在于,当服务被外部强制终止的时候,Notification仍然会移除。

 

为什么不使用线程

使用服务来进行一个后台长时间的动作其实就是为了不阻塞线程,然而,Thread 就可以达到这个效果,为什么不直接使用Thread去代替服务呢?两者的区别如下

    1Thread∶程序执行的最小单元,是分配CPU的基本单位,可以用来执行一些异步操作

2Service∶ Andriod 的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主进程的Main线程上的。例如,onCreate()onStart()这些函数在被系统调用的时候都是在主进程的Main线程上运行的。如果是Remote Service,那么对应的 Service是运行在独立进程的 Main线程上的。

通过对比可以发现两者完全不同,但是并没有说明为什么一定要使用 Service 而不是Thread。真正的原因和Android 的系统机制有关。Thread 的运行是独立于 Activity 的,也就是说当一个Actvity finish之后,如果没有主动停止Thread 或者 Thread 里的run 方法没有执行完毕,Thread就会一直执行。因此这里会出现一个问题Activityfinish之后,就不再持有该 Thread 的引用。另一方面,你没有办法在不同的Activity 中对同一Thread 进行控制

举个例子如果 Thread需要不停地隔一段时间就连接服务器做某种同步,那么该Thread 需要在Activity没有 start的时候就运行。这时 start一个 Activity 的话就没有办法在该Activity 里面控制之前创建的 Thread,因此需要创建并启动一个 Service,在 Service 里创建、运行并控制Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。

Service 的创建与启动

Service 不能自己运行,需要通过调用 Context.startService()或Context.bindService0方法启动服务。我们通常会把 Service 的两种启动方式称为 start 方式和 bind方式。下面我们概括性地介绍了这两种方式,具体代码层面的操作会在后面通过实例的方式向读者展现。

开启方式

一:start方式启动的Service

开启步骤

定义一个类继承 Service

Manifest.xml文件中配置该Service

使用Context startService()方法启动该Service

不使用时,调用 stopService()方法停止该服务

特点:

start方式启动的Service一旦开启就和开启者没有关系了,无论开启者退出或者被销毁,Service都依旧会运行。开启者无法调用服务中的方法。

二:以Bind方式启动的Service

定义一个类继承Service

Manifest.xml 文件中配置该Service

使用Context bindService(Intent intentServiceConection serviceConnectionint f)方法绑定 Service

不使用时调用unbindService(ServiceConection service-Connection)方法停止该服务。

特点:

bind方式开启(绑定)的Service,绑定者与服务绑定在了一起,绑定者一旦退出,服务就会终止,具有“不求同生,但求同死”的特点。绑定者可以调用服务中的方法

如果只是想要启动一个后台服务长期进行某项任务,使用 start方式就可以。想要与正在运行的Service 进行通信或者需要更新 Service 的状态,可以使用两种方法种是使用Broadcast后面的章节会讲解),另外一种是使用bind方式开启 Service。前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且. BroadcastReceiverBroadCast中的常用类,第9章会进行讲解)本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会行,在开发的实践中出现过类似情况),而后者则没有这些问题,因此我们选择使用 bind方式开启 Service

 当然,在 Android 开发实践中会经常出现两种开启方式混合使用的状态。 Service 生命周期

先来观察图 1-1,这是官方提供的 Service 的生命周期图。

1-1  官方提供的Service的生命周期图

通过图1-1 可以看出 Service的生命周期并不向 Activity 或者 Fragment 那样复杂,onCreate()onstartCommand()onDestroy()onBind()onUnbind()等几种。同时也可以看出Service的生命周期分为两种,正好应对着Service 的两种启动方式,分别如下所示start方式和bind方式开启服务时对应的生命周期

开启方式

一:start 方式

生命周期

onCreate()->onStarCommand()->Service running—--调用context.stopService()->onDestroy()

二:bind方式

onCreate()->onBind()->Service running——调用 context.unbindService()->onUnbind()->onDestroy()

具体来说,如果一个 Service被某个 Activity 调用Context.startService()方法启动,那么管是否有 Activity 使用 bindService()绑定或unbindService()解除绑定到Service,该Servie都在后台运行。同时,不管一个Service startService()方法启动几次,onCreate()方法也只会调用一次,onStart()方法将会被调用多次(对应调用 startService()的次数),并且系统只会创建Service 的一个实例,所以我们应该知道只需要一次stopService()方法的调用。该 Service 将会一直在后台运行,而不管对应程序的Activity 是否在运行,直到被调用stopService()或自身的stopSelf()方法。当然如果系统资源不足,Android 系统也可能结束服务。

如果一个 Service 被某个 Activity 调用 Context.bindService()方法绑定启动,那么不管bindService()方法被调用了几次,onCreate()方法都只会调用一次,同onStart()方法始终不会被调用。当连接建立之后,Service 将会一直运行,除非调用Context.unbindService*()断开连接或者之前调用 bindService() Context 不存在了(如 Activityfinish 的时候),系统将会自动停止 Service,对应 onDestroy()将被调用。

在上面的两种生命周期中,我们可以看到,不管使用哪种方式,都会在创建时调用onCreate()方法、在销毁时调用 onDestroy()方法。因此在开发中,我们会在 onCreate()方法中进行一些初始化的工作,而在 onDestroy()方法中进行一些清理工作。

另外,在前面提及同时以start方式和bind方式开启 Service的状况。此时需要注意的是需要同时调用 unbindService() stopService()才能终止 Service,而不管 unbindService()stopService()的调用顺序如何。先调用 unbindService(),此时服务不会自动终止,再调用stopService()之后服务才会停止;先调用 stopService(),此时服务也不会终止,再调用unbindServce()或者之前调用 bindService() Context不存在了(Activity finish())的时候之后服务才会自动停止。


作者: 大鸟科创空间, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-3949041.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

文章评论0条评论)

登录后参与讨论
我要评论
0
12
关闭 站长推荐上一条 /2 下一条