【Android】16.1 Android Service基本概念

分类:C#、Android、VS2015;

创建日期:2016-03-01

一、简介

为了解决在后台运行任务的问题,Android引入了一个称为Service的应用程序组件。Service的职责是专门用于创建、开始和停止在后台执行的任务,同时提供前台和后台交互的编程接口。

注意Android系统中所指的Service和我们平常所说的Web Service不是一回事,Android系统提供的Service只是一个应用程序组件,它能在后台执行一些耗时较长的无用户界面的操作。这种Service能被其它应用程序的组件启动,即使用户切换到另外的应用,它也能保持在后台继续运行。此外,应用程序组件还能与这些Service绑定,并与Sevice进行交互,甚至能进行进程间通信(IPC)。比如,利用Android Service可以处理网络传输、音乐播放、执行文件I/O、或者与content provider进行交互,所有这些都是在后台进行的。

Android Service的生命周期可能用时较短,也可能用时很长。比如,媒体播放器播放歌曲时,为了让用户感觉导航到其他屏幕时音乐还在继续播放,媒体播放器这个Activity就需要通过Context.StartService()方法启动一个Service在后台继续播放音乐。另外,还可以通过Context.BindService()方法将当前Activity绑定到一个后台Service(如果该Service未启动则自动启动它),当连接到该Service之后,还可以利用Sevice提供的接口与它进行通信,比如控制音乐的暂停、重播等动作。

二、Service的分类

对一个安卓服务(Android Service)来说,通常是要么将其作为已启动的服务(Started Service),要么将其作为已被绑定的服务(Bound Service)。

1、Started Service

已启动的服务(Started Service)是指被同一个应用程序的某个对象显式启动,或者在设备引导时就启动了(配置了服务的情况)。通常情况下,已启动的服务在操作系统或服务自身显式调用停止服务之前一直在运行。

2、Bound Service

被绑定的服务(Bound Service)提供直接链接到应用程序中特定的Service。它使用一个Binder提供对Service的引用,这样一来,应用程序就可以直接访问Service中的成员了。一般在同一个应用程序(通常是一个Activity)中的客户端启动时绑定到该Service,导致Android启动该服务,在客户端连接或绑定到它以后,安卓系统会保持被绑定的服务一直运行。当所有客户端断开连接或取消绑定时,Android才会停止该服务。

3、Hybrid Service

也可以将Started Service和Bound Service这两种服务混合在一起,称为混合式服务(Hybrid Service)。即:先显式启动某个服务,然后再绑定到该服务。这种方式的好处是也给别的应用程序提供了一个利用服务做其他事情的机会。换句话说,只要别的应用程序连接到该服务,就可以直接访问它。

混合式服务的办法非常有用,使用也非常普遍。比如说,我们正在编写一个在徒步旅行时跟踪运动位置的应用程序,我们可能想要不断地记录位置以便以后使用,但仅在需要屏幕显示时才去显示特定的位置信息。在这种情况下,当应用程序运行时,仅仅在客户端某一个Activity在前台运行的时候才可能会启动这个服务。该Activity绑定到该服务以后,就可以获取位置信息,但是,即使该Activity取消和这个服务的绑定,该服务仍能继续运行。换言之,混合服务(Hybrid Service)一旦启动起来就会一直运行,直到它被显式停止和没有客户端绑定到它才会关闭它,或者直到系统因为内存不够用时才会关闭它。

三、使用服务还是使用线程

如果你需要在主线程之外执行一些工作,但仅当用户与你的应用程序交互时才会用到它,那你应该创建一个新的线程而不是创建一个服务。比如,如果你需要播放音乐,但只是当你的activity在运行时才需要播放,此时可以在OnCreate()中创建一个线程,在OnStart()中开始运行,在OnStop()中终止运行。还可以考虑使用AsyncTask或HandlerThread来取代传统的Thread类。

要始终记住:

(1)如果你使用了服务,它默认运行在应用程序的主线程中。因此,如果服务执行的是密集计算型的工作,那么它可能会阻塞界面操作,这种情况下,你仍然应该在服务中创建一个新的线程来完成这些工作。

(2)创建自定义的服务时,必须新建一个继承自Service的类或其子类。另外,在实现代码中,还需要重写一些回调方法,这些回调方法用于对服务生命周期中的关键节点进行处理,以及向组件提供绑定机制。

这里再强调一遍,在Android系统中,服务仅仅是一个组件,即使用户不再与你的应用程序发生交互,它可能仍然能在后台运行着。因此,应该只在需要时才创建一个服务。

四、在AndroidManifest.xml中配置服务

用C#实现Android服务时,一般不直接修改清单文件(AndroidManifest.xml)。如果你想这么做当然也可以。不过,此时你要忍受修改AndroidManifest.xml文件时没有智能提示的痛苦。

下面简单说明如何直接在AndroidManifest.xml文件中配置Service。

要在配置文件中直接声明你的服务,只需要把<service>元素作为子元素加入到<application>元素中去即可。例如:

<manifest ... >
  ...
  <application ... >
      <service android:name="exampleservice.ExampleService" />
      ...
  </application>
</manifest>

其中,exampleservice是服务子类所在的命名空间(在配置文件中要把命名空间全部变为小写字母才可以),ExampleService是服务子类的类名,大小写均可。

android:name是唯一必需在配置文件中指定的属性——它定义了服务的完整类名。也可以在<service>元素中包含其它属性,比如定义启动服务所需权限、服务运行的进程之类的属性等。

与Activity一样,服务也可以定义intent过滤器。

通过声明intent过滤器,任何安装在用户设备上的应用程序组件都有能力来启动你的服务,只要你的服务所声明的intent过滤器与其它应用程序传递给StartService()的intent相匹配即可。

但是,如果你想让服务只能在你的应用程序内部使用(其它应用程序无法调用),那么就不必(也不应该)提供任何intent过滤器。 如果不存在任何intent过滤器,那你就必须用精确指定服务类名的intent来启动服务。

此外,如果服务配置中包含了android:exported属性并且将其设置为"false",即可确保该服务是你的应用程序的私有服务。即使服务提供了intent过滤器,本属性依然生效。

五、组件与Service的通信

组件与服务进行通信的方式取决于该服务运行的模式。Android提供了三个用于组件和Service进行通信的选项:Service Binding、Service Messengers、AIDL。

1、绑定服务

如果服务是同一个应用程序的一部分,客户端可以直接绑定到服务并直接与之通信。绑定到客户端的服务将重写绑定服务生命周期的方法,并使用Binder和ServiceConnection实现服务与客户端的通信。

2、消息服务

有时客户端需要与另一个应用程序中的服务进行通信,由于应用程序不能访问彼此的内存,因此不可能直接建立连接。此时,需要通过跨进程边界的进程间通信(IPC,Inter-Process Communication)来封送数据。在这种情况下,可以用消息服务跨进程边界,即允许客户端绑定到远程服务(RPC),并调用远程服务器上提供的Service来实现。

3、AIDL

AIDL是Android接口定义语言(Android Interface Definition Language)的缩写。这是跨进程边界通信的另一种方式。AIDL是一个低级别的接口,它对包含元数据类型的对象进行了封装,使其可以跨进程边界。但是,由于消息服务更易于使用,也更容易实现,因此自消息服务推出以来,已经在很大程度上取代了AIDL通信模式。但是,消息服务发送的消息是通过串行方式来实现的而不是用并行方式实现(注意不要把串行方式和异步方式混淆在一起),当需要“并发”调用跨进程边界的通信服务时,还是应该用AIDL来实现。不过,移动应用中需要用AIDL实现的情况并不多,因此,如果是初学者,也可以暂不考虑它。

总之,在实际应用中,其他组件和Service通信时,最常用的是前两种服务模式:绑定服务和消息服务。只有在需要并发执行的情况下才需要用AIDL去实现。

posted @ 2016-03-01 06:24  rainmj  阅读(763)  评论(0编辑  收藏  举报