Service类的继承关系如图13.1所示。
图13.1 Service类继承关系
13.1.3 Service的声明
类似于Activity和其他组件,开发人员必须在应用程序配置文件中声明全部的Service。为了声明Service,需要向
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
各个标签属性的说明如下:
[√]android:enabled
服务能否被系统实例化,true表示可以,false表示不可以,默认值是true。
[√]android:exported
其他应用程序组件能否调用服务或者与其交互,true表示可以,false表示不可以。当该值是false时,只有同一个应用程序的组件或者具有相同用户ID的应用程序能启动或者绑定到服务。
默认值依赖于服务是否包含Intent过滤器。若没有过滤器,说明服务仅能通过精确类名调用,这意味着服务仅用于应用程序内部(因为其他程序可能不知道类名)。此时,默认值是false;若存在至少一个过滤器,暗示服务可以用于外部,因此默认值是true。
该属性不是限制其他应用程序使用服务的唯一方式。还可以使用permission属性限制外部实体与服务交互。
[√]android:icon
表示服务的图标。该属性必须设置成包含图片定义的可绘制资源引用。如果没有设置,使用应用程序图标取代。
服务图标不管在此设置还是在
[√]android:label
显示给用户的服务名称。如果没有设置,使用应用程序标签取代。
服务标签不管在此设置还是在
标签应该设置为字符串资源引用,这样可以像用户界面的其他字符串那样本地化。然而,为了开发时方便,也可以设置成原始字符串。
[√]android:name
实现服务的Service子类名称,应该是一个完整的类名,如com.mingrisoft.RoomService。然而,为了简便,如果名称的第一个符号是点号(如.RoomService),则会增加在
一旦发布了应用程序,不应该再修改子类名称。该属性没有默认值并且必须指定。
[√]android:permission
实体必须包含的权限名称,以便启动或者绑定到服务。如果startService()、bindService()或stopService()方法调用者没有被授权,方法调用无效,并且Intent对象也不会发送给服务。
如果没有设置该属性,使用
[√]android:process
服务运行的进程名称。通常,应用程序的全部组件运行于为应用程序创建的默认进程。进程名称与应用程序包名相同。
如果分配给该属性的名称以冒号(:)开头,仅属于应用程序的新进程会在需要时创建,服务能在该进程中运行;如果进程名称以小写字母开头,服务会运行在以此为名的全局进程,但需要提供相应的权限。这允许不同应用程序组件共享进程,减少资源使用。
13.2 创建Started Service
教学录像:光盘\TM\lx\13\ 创建Started Service.exe
Started Service(启动服务)是由其他组件调用startService()方法启动的,这导致服务的onStartCommand()方法被调用。
当服务是started状态时,其生命周期与启动它的组件无关,并且可以在后台无限期运行,即使启动服务的组件已经被销毁。因此,服务需要在完成任务后调用stopSelf()方法停止,或者由其他组件调用stopService()方法停止。
应用程序组件(如Activity)能通过调用startService()方法和传递Intent对象来启动服务,在Intent对象中指定了服务并且包含服务需要使用的全部数据。服务使用onStartCommand()方法接收Intent。
例如,假设Activity需要保存一些数据到在线数据库。Activity可以启动伴侣服务并通过传递Intent到startService()方法来发送需要保存的数据。服务在onStartCommand()方法中收到Intent,联入网络并执行数据库事务。当事务完成时,服务停止自身并销毁。
Android提供了两个类供开发人员继承以创建启动服务。
[√]Service:这是所有服务的基类。当继承该类时,创建新线程来执行服务的全部工作是非常重要的。因为服务默认使用应用程序主线程,这可能降低应用程序Activity的运行性能。
[√]IntentService:这是Service类的子类,它每次使用一个工作线程来处理全部启动请求。在不必同时处理多个请求时,这是最佳选择。开发人员仅需要实现onHandleIntent()方法,该方法接收每次启动请求的Intent以便完成后台任务。
13.2.1 继承IntentService类
因为多数启动服务不必同时处理多个请求(在多线程情境下会很危险),所以使用IntentService类实现服务是非常好的选择。IntentService可完成如下任务:
[√]创建区别于应用程序主线程的默认工作线程来执行发送到onStartCommand()方法的全部Intent。
[√]创建工作队列,每次传递一个Intent到onHandleIntent()方法实现,这样就不必担心多线程。
[√]所有启动请求处理完毕后停止服务,这样就不必调用stopSelf()方法。
[√]提供onBind()方法默认实现,其返回值是null。
[√]提供onStartCommand()方法默认实现,它先发送Intent到工作队列,然后到onHandleIntent()方法实现。