1.Service简介
服务是一个应用程序组件,可以在后台执行长时间运行的操作,不提供用户界面。一个应用程序组件可以启动一个服务,它将继续在后台运行,即使用户切换到另一个应用程序。此外,一个组件可以绑定到一个服务与它交互,甚至执行进程间通信(IPC)。例如,一个服务可能处理网络通信、播放音乐、计时操作或与一个内容提供者交互,都在后台执行。
2.Service的种类
- 按运行地点分类:
类别 | 区别 | 优点 | 缺点 | 应用 |
---|---|---|---|---|
本地服务(Local Service) | 该服务依附在主进程上 | 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会 方便很多。 |
主进程被Kill后,服务便会终止。 | 如:音乐播放器播放等不需要常驻的服务。 |
远程服务(Remote Service) | 该服务是独立的进程 | 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process 字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。 |
该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。 | 一些提供系统服务的Service,这种Service是常驻的。 |
- 按运行类型分类:
类别 | 区别 | 应用 |
---|---|---|
前台服务 | 会在通知栏显示onGoing的 Notification | 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。 |
后台服务 | 默认的服务即为后台服务,即不会在通知一栏显示 onGoing的 Notification。 | 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。 |
- 按使用方式分类:
类别 | 区别 |
---|---|
startService启动的服务 | 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService。 |
bindService启动的服务 | 方法启动的服务要进行通信。停止服务使用unbindService。 |
同时使用startService、bindService 启动的服务 | 停止服务应同时使用stopService与unbindService。 |
3.Service的生命周期
通过这个图可以看到,两种启动Service的方式以及他们的生命周期,bindService的不同之处在于当绑定的组件销毁后,对应的service也就被kill了。
- 被启动的服务的生命周期
一个Service被使用startService
方法启动,不管是否调用了bindService
(绑定服务)或unbindService
(解除绑定服务)到该Service,该Service都会在后台运行并不受影响。
一个Service被使用startService
方法启动多少次,onCreate方法只会调用一次,onStartCommand方法将会被调用多次(与startService
的次数一致),且系统只会创建一个Service实例(结束该Service也只需要调用一次stopService
),该Service会一直在后台运行,直至调用stopService
或调用自身的stopSelf
方法。
注:在系统资源不足的情况下,服务有可能被系统结束(kill);
被绑定的服务的生命周期
如果一个Service在某个Activity中被调用bindService
方法启动,不论bindService
被调用几次,Service的onCreate方法只会执行一次,同时onStartCommand方法始终不会调用。
当建立连接后,Service会一直运行,除非调用unbindService
来接触绑定、断开连接或调用该Service的Context不存在了(如Activity被Finish——即通过bindService
启动的Service的生命周期依附于启动它的Context),系统在这时会自动停止该Service。被启动又被绑定的服务的生命周期
当一个Service在被启动(startService
)的同时又被绑定(bindService
),该Service将会一直在后台运行,并且不管调用几次,onCreate方法始终只会调用一次,onStartCommand的调用次数与startService
调用的次数一致(使用bindService
方法不会调用onStartCommand)。同时,调用unBindService
将不会停止Service,必须调用stopService
或Service自身的stopSelf
来停止服务。
官方原文:
If you do allow your service to be started and bound,then when then service has been started,the System does not destory the service when all clients unbind.Instead,you must explicitly stop the service,by calling stopSelf()
or stopService()
.
如果你同意你的服务被开启和绑定,然后当服务被开启的时候,当所有的客户端都解除对服务的绑定android操作系统也不会销毁这个服务,相反的你必须显示的调用stopSelf()或者stopService()方法来停止服务。
什么情况下使用:
如果你想要与正在运行的Service取得联系,那么有两种方法,一种是使用广播,另外一种方法就是使用bindService来建立联系,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且BroadcastReceiver本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用bindService(这个时候你便同时在使用startService和bindService了,这在Activity中更新Service的某些运行状态是相当有用的)。
- 当服务被停止时
当一个服务被终止(stopService
、stopSelf
、unbindService
)时,onDestory方法将会被调用——所以我们需要在该方法中清除一些工作(依附该Service生命周期的,如:停止在Service中创建并运行的线程)。
特别注意:
1.在使用startService
方法启动服务后,一定要调用stopService
方法来停止该服务(同上,可以在Activity的onDestory中来停止服务);
2.在某处调用bindService
绑定Service的时候,要在对应的某处调用unbindService
来解除绑定(如在Activity中绑定了Service,可以在onDestory中来解除绑定——虽然绑定的Service会在Activity结束时自动解除、停止);
3.如果同时使用startService
与bindService
方法启动Service,需要终止该Service时,要调用stopService
和unbindService
方法(unbindService
依附于启动它的Context,startServicec
并不依附于启动它的Context。如果先调用unbindService
,这时服务并不会被终止,当调用stopService
后,服务才会被终止;如果先调用stopService
,服务也不会被终止,当调用unbindService
或者之前调用bindService
的Context不存在了(如Activity被finish掉了)服务才会自动停止);
4.当手机屏幕发生旋转时,如果Activity设置的是自动旋转的话,在旋转的过程中,Activity会重新创建,那么之前通过bindService
建立的连接便会断开(之前的Context不存在了),服务也会被自动停止。
4.Service的使用
在新建一个Service后,记得在AndroidManifest.xml中注册Service,在application内添加需要注册的Service信息:
Service示例如下:
public class PlayerService extends Service{
@Override
public void onCreate() {
super.onCreate();
}
/**
* onBind 是 Service 的虚方法,因此我们不得不实现它。
* 返回 null,表示客服端不能建立到此服务的连接。
*/
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
// 已取代onStart方法--onStart方法是在Android2.0之前的平台使用的.
// 在2.0及其之后,则需重写onStartCommand方法,同时,旧的onStart方法则不会再被直接调用
// (外部调用onStartCommand,而onStartCommand里会再调用 onStart。在2.0之后,
// 推荐覆盖onStartCommand方法,而为了向前兼容,在onStartCommand依然会调用onStart方法。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
// IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程
// 调用,也用于进程内调用。这个接口定义了与远程对象交互的协议。
// 不要直接实现这个接口,而应该从Binder派生。
// Binder类已实现了IBinder接口
class MyBinder extends Binder {
/**
* 获取Service的方法
* @return 返回PlayerService
*/
public PlayerService getService(){
return PlayerService.this;
}
}
}
- startService启动服务
通过startService()
启动的服务处于“启动”状态,一旦启动,Service就在后台运行,即使启动它的应用组件已经被销毁了。通常started状态的Service执行单任务并且不返回任何结果给启动者(如当下载或上传一个文件,当这项操作完成时,Service应该停止它本身),示例如下:
public class PlayerActivity extends Activity{
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, PlayerService.class);
startService(intent);// 启动服务
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);// 在退出Activity时停止该服务
}
}
- bindService绑定服务
一个绑定的Service提供一个允许组件与Service交互的接口,可以发送请求、获取返回结果,还可以通过跨进程通信来交互(IPC)。绑定的Service只有当应用组件绑定后才能运行,多个组件可以绑定一个Service,当调用unbindService()
方法时,这个Service就会被销毁了。 - Local(本地服务)的绑定
public class PlayerActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, PlayerService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);//绑定目标Service
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);// 解除绑定,断开连接
}
// 在Activity中,我们通过ServiceConnection接口来取得建立连接与连接意外丢失的回调
ServiceConnection serviceConnection = new ServiceConnection() { @Override
public void onServiceConnected(ComponentName name, IBinder service){
// 建立连接
// 获取服务的操作对象
PlayerService.MyBinder binder = (PlayerService.MyBinder)service;
binder.getService();// 获取到的Service即PlayerService
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 连接断开
}
};
}
注
Service的onBind
如果返回null,则调用bindService
会启动Service,但不会连接上Service因此ServiceConnection.onServiceConnected不会被调用,但仍然需要使用unbindService
方法来断开连接,这样Service才会停止。
- Remote(远程服务)的绑定
【Android】远程服务(Remote Service)的使用 - 前台服务的使用
请访问【Android】Service前台服务的使用
注
Service与Activity一样都存在与当前进程的主线程中,所以,一些阻塞UI的操作(如在Service进行网络请求等)不能放在Service里进行。如果在Service里进行一些耗CPU和耗时操作,可能会引发ANR警告,这时应用会弹出是强制关闭还是等待的对话框。所以,对Service的理解就是和Activity平级的,只不过是看不见的,在后台运行的一个组件,这也是为什么和Activity同被说为Android的基本组件。
5. AndroidManifest.xml中Service元素常见属性
- andorid:name
服务类名。可以是完整的包名+类名。也可使用
.
代替包名。
- adroid:exported
其他应用能否访问该服务,如果不能,则只有本应用或有相同用户ID的应用能访问。默认为false。
- android:enabled
标识服务是否可以被系统实例化。true--系统默认启动,false--不启动。(默认值为true)
- android:label
显示给用户的服务名称。如果没有进行服务名称的设置,默认显示服务的类名。
- android:process
服务所运行的进程名。默认是在当前进程下运行,与包名一致。如果进行了设置,将会在包名后加上设置的集成名。
如果名称设置为冒号:
开头,一个对应用程序私有的新进程会在需要时和运行到这个进程时建立。如果名称为小写字母开头,服务会在一个相同名字的全局进程运行,如果有权限这样的话。这允许不同应用程序的组件可以分享一个进程,减少了资源的使用。
- android:icon
服务的图标。
- android:permission
申请使用该服务的权限,如果没有配置下相关权限,服务将不执行,使用
startService()
、bindService()
方法将都得不到执行。
6.Thread与Service的区别
- Thread的优先级低于Service的优先级,在系统资源紧张的情况下,优先杀死前者;
- 在Thread启动后,如果退出当前Activity,则无法对已经启动的Thread进行操作,而服务则可以——因此可以在服务中启动Thread来解决该问题;
- Service可以进行跨进程访问,而Thread不行;
- 在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用Service;
- 同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需需要长时间运行的情况下使用Thread;
- 如果任务占用CPU时间多,资源大的情况下,要使用Thread。
- 拓展阅读
Thread和Service应用场合的区别
Android中Service与Thread的区别
android-Service和Thread的区别
7.Service系列拓展阅读
【Android】Service前台服务的使用
【Android】远程服务(Remote Service)的使用