
2.3 Service
Service是Android四大组件之一,是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。除非系统必须回收内存资源,否则系统不会停止或销毁服务。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信(IPC)。服务能够被其他组件启动、绑定、交互、通信。
2.3.1 Service的创建和生命周期
普通的Service的生命周期很简单,分别是onCreate、onStartCommand、onDestroy这三个。当我们startService()的时候,首次创建Service会回调onCreate()方法,然后回调onStartCommand()方法,再次startService()的时候,就只会执行onStartCommand()。服务一旦开启后,我们就需要通过stopService()方法或者stopSelf()方法关闭服务,这时就会回调onDestroy()。
1.生命周期状态
Service的生命周期如图2-8所示。

图2-8 Service的生命周期
2.生命周期方法
Service的生命周期方法如表2-1所示。
表2-1 生命周期方法

(续)

手动调用的方法如表2-2所示。
表2-2 手动调用的方法

3.生命周期调用
1)启动Service服务。
单次:startService()→onCreate()→onStartCommand()
多次:startService()→onCreate()→onStartCommand()→onStartCommand()。
2)停止Service服务:stopService()→onDestroy()。
3)绑定Service服务:bindService()→onCreate()→onBind()。
4)解绑Service服务:unbindService()→onUnbind()→onDestroy()。
5)启动绑定Service服务:startService()→onCreate()→onStartCommand()→bindService()→onBind()。
6)解绑停止Service服务:unbindService()→onUnbind()→stopService()→onDestroy()。
7)解绑绑定Service服务:unbindService()→onUnbind(ture)→bindService()→onRebind()。
【例2-7】 创建Service和生命周期的使用



用Android Studio创建项目,执行结果如图2-9和图2-10所示。

图2-9 执行结果

图2-10 模拟器效果
说明:
1)建立项目myservice,并在com.example.myservice中创建BackGroupService.java。BackGroupService继承Service类重写了onBind()、onCreate()、onStartCommand()和onDestroy()四个方法。
2)MainActivity.java定义两个button变量,将button变量设置监听事件,通过判断按钮id来控制操作。通过两个按钮分别演示启动服务和停止服务,通过startService()开启服务,通过stopService()停止服务。
3)创建一个服务非常简单,只要继承Service,并实现onBind()方法。
4)Service也是四大组件之一,所以必须在AndroidManifest中配置。

2.3.2 本地Service
Local Service用于应用程序内部,服务和启动服务的Activity在同一个进程中。它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,以调用Context.stopService()结束。它可以调用Service.stopSelf()或Service.stopSelfResult()来自动停止。不论调用了多少次startService()方法,用户只需要调用一次stopService()来停止服务。
用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序(比如Activity所属线程),而是单开线程在后台执行,这样用户体验比较好。
实现步骤如下:
1)在Service中实现抽象方法onBind(),并返回一个实现IBinder接口的对象。
2)在Activity中通过ServiceConnection接口来获取连接建立与连接断开的回调。
3)bindService(Intent intent,new myConn(),BIND_AUTO_CREATE)方法绑定服务,接收三个参数。第一个参数是intent对象,指定当前活动要连接的Service,与startService中的Intent一致;第二个参数是实现了ServiceConnection接口的对象,实现其中的两个方法,分别在服务绑定后和解绑后且onBind()方法返回方法不为null时调用;第三个是flag标志位。有两个flag,Context.BIND_DEBUG_UNBIND与Context.BIND_AUTO_CREATE,前者用于调试,后者默认使用。
4)unbindService(connection)方法解除绑定,参数则为之前创建的ServiceConnection接口对象。另外,多次调用unbindService()来释放相同的连接会抛出异常,需要添加判断是否unbindService已经被调用过。
注意:
● startService()方法开启的服务开启后一直在后台运行,除非用户手动停止,且可以通过设置页面看到。
● bindService()方法开启的服务如不解绑则会和活动一同销毁,且无法在设置页面看到。
2.3.3 远程Service
远程服务(Remote Service)也被称之为独立进程,它不受其他进程影响,可以为其他应用程序提供调用的接口——实际上就是进程间通信IPC(Inter-Process Communication),Android提供了AIDL(Android Interface Definition Language,接口描述语言)工具来帮助进程间接口的建立。
在远程服务中,通过Service的onBind(),在客户端与服务器端建立连接,通过调用Context.unbindService()关闭服务连接。多个客户端可以绑定至同一个服务,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
远程服务开启实现步骤如下:
1)定义AIDL接口,如IServiceInterface.aidl。
2)Client连接Service,连接到IServiceInterface暴露给Client的Stub,获得Stub对象;即Service通过接口中的Stub向Client提供服务,在IServiceInterface中对抽象IServiceInterface.Stub具体实现。
3)Client和Service连接后,Client可像使用本地方法那样直接调用IServiceInterface.Stub里面的方法。Service调用时需要注意下面几点。
● 同一应用的Activity与Service也可以在不同进程间,可以在Service配置中设置android:process=":remote"。
● 在不同的进程之间传递数据,Android对这类数据的格式支持非常有限,基本上只能传递Java的基本数据类型、字符串、List或Map等。如果想传递一个自定义的类必须要让这个类去实现Parcelable接口,并且给这个类也定义一个同名的AIDL文件。
● SDK5.0后调用远程服务需要指定包名:intent.setPackage("PackageName");
注意:Service.onBind()如果返回null,则调用bindService会启动Service,但不会连接上Service,因此ServiceConnection.onServiceConnected不会被调用,但仍然需要使用unbindService函数断开它,这样Service才会停止。
【例2-8】 远程Service和Client端调用
1)新建Remote Service。
在远程服务中,通过Service的onBind(),在客户端与服务器端建立连接时,用来传递Stub(存根)对象。

2)在AndroidManifest.xml中对Remote Service进行如下配置。

3)在客户端中建立与Remote Service的连接,获取Stub,然后调用Remote Service提供的方法来获取对应数据。


4)创建下面的布局文件。


运行结果如图2-11和图2-12所示。

图2-11 模拟器结果

图2-12 执行结果