第
5 
章

Android服务(Service) 

本章要点

. 
Service组件的作用和意义
. 
Service与Activity的区别
. 
运行Service的两种方式
. 
绑定Service执行的过程
. 
Service的生命周期
. 
跨进程调用Service 
. 
调用系统发短信服务
本章知识结构图


本章示例

根据Activity 
的生命周期,程序中每次只有一个Activity 
处于激活状态,并且
Activity的执行时间有限,不能做一些比较耗时的操作。如果需要多种工作同时进行,比
如一边听音乐,一边浏览网页,使用Activity则比较困难。针对这种情况,Android为我
们提供了另一种组件———服务(Service)。


Android编程(第2版) 


5.1 
Service概述
Service是一种Android应用程序组件,可在后台运行一些耗时但不显示界面的
操作。

5.1 
Srie介绍
1.evc

Service与Activity类似,都是Android中四大组件之一,并且二者都是从Context派
生而来,最大的区别在于Service没有实际的界面,而是一直在Android系统的后台运行, 
相当于一个没有图形界面的Activity程序,它不能自己直接运行,需要借助Activity或其
他Context对象启动。

Service主要有两种用途:后台运行和跨进程访问。通过启动一个Service,可以在不
显示界面的前提下在后台运行指定的任务,这样可以不影响用户做其他事情,如后台播放
音乐,前台显示网页信息。AIDL 服务可以实现不同进程之间的通信,这也是Service的
重要用途之一。

其他的应用程序组件一旦启动Service,该Service将会一直运行,即使启动它的组件
跳转到其他页面或销毁。此外,组件还可以与Service绑定,从而与之进行交互,甚至执行
一些进程内通信。例如,服务可以在后台执行网络连接、播放音乐、执行文件操作或者是
与内容提供者交互等。

5.1.2 
启动Service的两种方式
在Android系统中,常采用以下两种方式启动Service。

120 


第5章Android服务(Service) 

(1)通过Context的startService()启动Service。启动后,访问者与Service之间没
有关联,该Service将一直在后台执行,即使调用startService的进程结束了,Service仍然
还存在,直到有进程调用stopService(),或者Service自杀(stopSelf())。这种情况下, 
Service与访问者之间无法进行通信和数据交换,往往用于执行单一操作,并且没有返回
结果。例如通过网络上传、下载文件,操作一旦完成,服务应该自动销毁。
(2)通过Context的bindService()绑定Service。绑定后,Service就和调用
bindService()的组件“同生共死”了,也就是说当调用bindService()的组件销毁了,它
绑定的Service也要跟着结束,当然期间也可以调用unbindService()让Service提前
结束。
注意:一个Service可以与多个组件绑定,只有当所有的组件都与之解绑后,该
Service才会被销毁。

以上两种方式也可以混合使用,即一个Service既可以启动也可以绑定,只需要同时
实现onStartCommand()(用于启动)和onBind()(用于绑定)方法,那么只有当调用
stopService(),并且调用unbindService()方法后,该Service才会被销毁。

注意:Service运行在它所在进程的主线程。Service并没有创建它自己的线程,也没
有运行在一个独立的进程上(单独指定的除外),这意味着,如果Service做一些消耗CPU 
或者阻塞的操作,应该在服务中创建一个新的线程去处理。通过使用独立的线程,就会降
低程序出现ANR(ApplicationNoResponse,程序没有响应)风险的可能,程序的主线程
仍然可以保持与用户的交互。

5.3 
Srie中常用方法
1.evc

与开发其他Android组件类似,开发Service组件需要先开发一个Service子类,该类
需继承系统提供的Service类,系统中Service类包含的方法主要有以下几种。

(1)abstractIBinderonBind(Intentintent):该方法是一个抽象方法,因此所有
Service的子类必须实现该方法。该方法将返回一个IBinder对象,应用程序可通过该对
象与Service组件通信。

(2)voidonCreate():当Service第一次被创建时,将立即回调该方法。

(3)voidonDestroy():当Service被关闭之前,将回调该方法。

(4)vintrCnItnnet,itfas,ntrId)

odoSatommad(netitnnlgitsat:该方法的早期版本
是vodoSat(netitnntrId), trSrie(netitn

intrItnnet,itsat每次客户端调用satevcItnnet) 
方法启动该Service时都会回调该方法。
(5)boenoid(netitnevc

olanUnbnItnnet):当该Srie上绑定的所有客户端都断开连
接时将会回调该方法。

定义的Service子类必须实现onBind()方法,然后还需在AndroidManifestxml文件
中对该Service子类进行配置,配置时可通过<intent-filter.
/>元素指定它可(.) 被哪些
Intent启动。下面具体来创建一个Service子类并对它进行配置,代码如下。

121

Android编程(第2版) 
1 22 
程序清单:codes\ch05\ServiceTest\app\src\main\java\ 
iet\jxufe\cn\servicetest\MyService.java 
1 public class MyService extends Service { →自定义服务类
2 private static final String TAG ="MyService"; →定义字符串常量
3 public IBinder onBind(Intent arg0) { →重写onBind()方法
4 Log.i(TAG, "MyService onBind invoked!"); →打印日志信息
5 return null; 
6 } 
7 public void onCreate() { →重写onCreate()方法
8 super.onCreate(); →调用父类方法
9 Log.i(TAG, "MyService onCreate invoked!"); →打印日志信息
10 } 
11 public void onDestroy() { →重写onDestroy()方法
12 super.onDestroy(); →调用父类方法
13 Log.i(TAG, "MyService onDestroy invoked!"); →打印日志信息
14 } 
15 public int onStartCommand(Intent intent, int flags, int startId) { 
→重写方法
16 Log.i(TAG, "MyService onStartCommand invoked! ") ; →打印日志信息
17 return super.onStartCommand(intent, flags, star tI d) ; →返回结果
18 } 
19 } 
上述代码中创建了自定义的MyService类,该类继承了Android.app.Service类,并
重写了onBind()、onCreate()、onStartCommand()、onDestroy()等方法,在每个方法中, 
通过LOG语句测试和查看该方法是否被调用。
定义Service之后,还需在项目的AndroidManifest.xml文件中配置该Service,增加
配置片段如下。 
1 <service android:name=“.MyService”> →Service 标签
2 <intent-filter> →过滤条件
3 <action android:name=“iet.jxufe.cn.MY_SERVICE”/> 
4 </intent-filter> 
5 </service> 
虽然目前MyService已经创建并注册了,但系统仍然不会启动MyService,要想启动
这个服务,必须显式地调用startService()方法。如果想停止服务,需要显式地调用
stopService()方法。下面的代码使用Activity作为Service的启动者,分别定义了“启动
服务”和“关闭服务”两个按钮,并为它们添加了事件处理。
程序清单:codes\ch05\FirstService\src\iet\jxufe\cn\android\MainActivity.java 
1 public class MainActivity extends AppCompatActivity { 
2 private Intent intent; →声明Intent

第5章 Android服务(Service) 
1 23 
3 @Override 
4 protected void onCreate(Bundle savedInstanceState) { 
5 super.onCreate(savedInstanceState); 
6 setContentView(R.layout.activity_main); →加载布局文件
7 intent=new Intent(this,MyService.class); →创建Intent 对象
8 } 
9 public void start(View view){ →按钮事件处理
10 startService(intent); →启动服务
11 } 
12 public void stop(View view){ →按钮事件处理
13 stopService(intent); →停止服务
14 } 
15 } 
运行本节的例子后,第一次单击“启动服务”按钮后,LogCat视图下的输出如图5-1 
所示。
图5-1 启动ServiceLogCat控制台打印信息
然后单击“停止服务”按钮,LogCat视图有如图5-2所示的输出。
图5-2 关闭ServiceLogCat控制台打印信息
下面按如下的单击按钮顺序的重新测试一下本例。
“启动服务”→“启动服务”→“启动服务”→“停止服务” 
测试程序完成,查看LogCat控制台输出信息如图5-3所示。系统只在第一次单击
“启动服务”按钮时调用onCreate()和onStartCommand()方法,再单击该按钮时,系统只
会调用onStartCommand()方法,而不会重复调用onCreate()方法。
图5-3 连续启动ServiceLogCat控制台打印信息
启动服务后退出该程序,查看LogCat控制台输出信息,发现并没有打印onDestroy()方
法被调用的信息,即服务并没有销毁,可以通过查看系统服务,查看该服务是否正在运行, 
具体操作为:打开模拟器功能清单中的“设置”,选择“关于模拟设备”,然后连续单击版本
号7次进入开发者模式,接着退出“关于模拟设备”,进入“系统选项”,选择“高级”下面的

Android编程(第2版
)
“开发者选项”,即可看到正在运行的服务,如图5-4所示
。



图5-
4 
查看系统正在运行的服务

5.1.4 
绑定Service过程
如果使用5.1.2节介绍的方法启动服务,并且未调用stopService() 来停止服务, 
Service将会一直驻留在手机的服务之中。Service会在Android系统启动后一直在后台
运行,直到Android系统关闭后Service才停止。但这往往不是我们所需要的结果,我们
希望在启动服务的Activity关闭后Service会自动关闭,这就需要将Activity和Service 
绑定。在Context类中专门提供了一个用于绑定Service的bindService() 方法,Context 
的bindService() 方法的完整方法签名为:bindService(Intentservice,ServiceConnection 
conn,intflags), 该方法的三个参数解释如下。

(1)service:该参数表示与服务类相关联的Intent对象,用于指定所绑定的Service 
应该符合哪些条件。

(2)conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service 
间的连接。当访问者与Service间连接成功时,将回调该ServiceConnection对象的
onevcCnetd(ompnname,neevc方法; evc

SrieonceCoetNamenIBidrsrie) 当访问者与Srie 
之间断开连接时将回调该ServiceConnection 对象的onServiceDisconnected 
(ComponentNamename)方法。

(3)flags:指定绑定时是否自动创建Service(如果Service还未创建), 该参数可指定
BIND_AUTO_CREATE(自动创建)。
当定义Service类时,该Service类必须提供一个onBind() 方法,在绑定本地Service 
的情况下,onBind() 方法所返回的IBinder对象将会传给ServiceConnection对象里

124

第5章 Android服务(Service) 
1 25 
onServiceConnected(ComponentNamename,IBinderservice)方法的service参数,这样
访问者就可以通过IBinder对象与Service进行通信。
在上述示例中,添加两个按钮,一个用于绑定Service,一个用于解绑,然后分别为其
添加事件处理。在绑定Service时,需要传递一个ServiceConnection对象,所以先创建该
对象。在MainActivity.java中添加如下代码。 
1 private ServiceConnection conn=new ServiceConnection() { 
2 public void onServiceDisconnected(ComponentName name) { 
3 Log.i(TAG,"MainActivity onServiceDisconnected invoked!"); 
4 } 
5 public void onServiceConnected(ComponentName name, IBinder service) { 
6 Log.i(TAG,"MainActivity onServiceConnected invoked!"); 
7 } 
8 }; 
然后在MyService中添加两个与绑定Service相关的方法onUnbind()和onRebind(),与
其他方法类似,只在方法体中打印出该方法被调用了的信息,代码如下。 
1 public boolean onUnbind(Intent intent) { 
2 Log.i(TAG, "MyService onUnbind invoked!"); →打印日志信息
3 return super.onUnbind(intent); →调用父类方法
4 } 
5 public void onRebind(Intent intent) { 
6 super.onRebind(intent); →调用父类方法
7 Log.i(TAG, "MyService onRebind invoked!"); →打印日志信息
8 } 
最后在MainActivity中为“绑定服务”和“解绑服务”按钮添加事件处理,代码如下。 
1 public void bind(View view){ →绑定服务事件处理
2 bindService(intent,conn, Service.BIND_AUTO_CREATE); →绑定服务
3 } 
4 public void unbind(View view){ →解绑服务事件处理
5 unbindService(conn); →解绑服务
6 } 
程序执行后,单击“绑定服务”按钮,LogCat控制台打印信息如图5-5所示,首先调用
onCreate()方法,然后调用onBind()方法。
图5-5 绑定服务LogCat控制台打印信息
单击“解绑服务”按钮,LogCat控制台打印信息如图5-6所示,首先调用onUnbind() 
方法,然后调用onDestroy()方法。

Android编程(第2版) 
1 26 
图5-6 解绑服务LogCat控制台打印信息
程序运行后,单击“绑定服务”按钮,然后退出程序,LogCat控制台打印信息如图5-7 
所示。可以看出,程序退出后,Service会自动销毁。
图5-7 绑定服务直接退出程序LogCat控制台打印信息
当单击“绑定服务”按钮后,再重复多次单击“绑定服务”按钮,查看控制台打印信息, 
发现程序并不会多次调用onBind()方法。
采用绑定服务的另一个优势是组件可以与Service之间进行通信,传递数据。这主要
是通过IBinder对象进行的,因此需在Service中创建一个IBinder对象,然后让其作为
onBind()方法的返回值返回,对数据的操作是放在IBinder对象中的。修改MyService 
类,添加一个内部类MyBinder,同时在onCreate()方法中启动一个线程,模拟后台服务, 
该线程主要做数据递增操作,在MyBinder类中,提供一个方法,可以获取当前递增的值
(count的值),具体代码如下。 
1 public class MyService extends Service { 
2 private static final String TAG ="MyService"; 
3 private int count=0; 
4 private boolean quit=false; →是否退出的标志
5 private MyBinder myBinder=new MyBinder(); →创建对象
6 public class MyBinder extends Binder { 
7 public MyBinder() { →构造方法
8 Log.i(TAG, "MyBinder Constructure invoked!"→);打 印 日志信息
9 } 
10 public int getCount() { →获取数据方法
11 return count; →返回数据
12 } 
13 } 
14 public IBinder onBind(Intent arg0) { →重写onBind 方法
15 Log.i(TAG, "MyService onBind invoked!"); →打印日志信息
16 return myBinder; →返回对象
17 } 
18 public void onCreate() { 
19 Log.i(TAG, "MyService onCreate invoked!"); 
20 super.onCreate();

第5章 Android服务(Service) 
1 27 
21 new Thread(){ →创建线程
22 public void run(){ 
23 while(!quit){ →判断是否退出
24 try{ 
25 Thread.sleep(500); →休眠0.5s 
26 count++; →数据递增
27 }catch (Exception e) { →捕获异常
28 e.printStackTrace(); →打印异常信息
29 } 
30 } 
31 } 
32 }.start(); →启动线程
33 } 
34 public void onDestroy() { →重写方法
35 Log.i(TAG, "MyService onDestroy invoked!"); →打印日志信息
36 super.onDestroy(); →调用父类方法
37 quit=true; →修改退出标志
38 } 
39 } 
接着在MainActivity中添加一个“获取数据”的按钮,获取数据的前提是要绑定服
务,所以先绑定服务,在ServiceConnection()对象的onServiceConnected()方法中,获取
绑定服务时返回的IBinder对象,然后将该对象强制类型转换成MyBinder对象,最后利
用MyBinder对象获取服务中的数据信息, 
首先改写创建ServiceConnection对象的方法,将绑定服务中的IBinder对象强制类
型转换成MyService.MyBinder对象,关键代码如下。 
1 private ServiceConnection conn=new ServiceConnection() { 
2 public void onServiceDisconnected(ComponentName name) { 
3 Log.i(TAG,"MainActivity onServiceDisconnected invoked!"); 
4 } 
5 public void onServiceConnected(ComponentName name, IBinder service) { 
6 Log.i(TAG,"MainActivity onServiceConnected invoked!"); 
7 myBinder=(MyService.MyBinder)service; 
8 } 
9 }; 
然后,为“获取数据”按钮添加事件处理方法,关键代码如下。 
1 public void getData(View view){ →事件处理方法
2 Toast.makeText(MainActivity.this, "Count="+myBinder.getCount(), 
Toast.LENGTH_SHORT).show(); →弹出显示数据
3 } 
此时,单击“绑定服务”后,LogCat 控制台打印信息如图5-8 所示,首先创建

Android编程(第2版) 

MyBinder对象,因为该对象是作为MyService的成员变量进行创建的,完成MyService 
的初始化工作,然后调用onCreate() 方法,再调用onBind() 方法,该方法返回一个IBinder 

对象,因为IBinder对象不为空,表示有服务连接,所以会调用ServiceConnection接口的
onServiceConnected() 方法,并将IBinder对象作为它的第二个参数。


图5-
8 
绑定ServiceLogCat控制台打印信息

单击“绑定服务”按钮后,后台服务就开始执行,此时单击“获取数据”按钮,得到如
图5-9所示结果。多次单击时,得到的数据不一致,从而可以动态获取后台服务状态。


图5-
9 
单击“获取数据”按钮的运行效果

当混合使用这两种运行Service方式时,它的执行效果又将是怎么样的呢? 下面我们
以不同的顺序来运行服务,观察LogCat控制台打印的信息。

(1)先启动Service,然后绑定Service。测试步骤为单击“启动服务”→“绑定服务”→ 
“启动服务”→“停止服务”→“绑定服务”→“解绑服务”。LogCat控制台打印信息如图5-10 
所示。
总结:调用顺序为onCreate()→[onStartCommand() 1~
N 
次]→onBind()→ 
onServiceConnected()→onUnbind()[→onServiceConnected()→onRebind()0~
N 
次] 
→onDestroy()。

(2)先绑定Service,后启动Service。测试步骤为单击“绑定服务”→“启动服务”→“绑定
128