下面主要讲本地Service:
什么是Service:
Service
是android系统四大组件之一, Service主要有两个作用:
- 长驻后台,运行一些任务(例如:1. 你需要在后台每隔一段时间就执行某个任务,即使activity退出了)
- Service可以被跨进程访问
注意
:
- Service不是一个单独的进程,它和应用程序共享同一个进程。
- Service不是一个线程,它运行在应用程序的主线程(所以你要进行耗时操作的话,可以在service里另开一个线程,否则会阻塞主线程)
这里可能你会问一个问题:如果Service和应用程序运行在同一个主线程,那么为什么Activity退出后Service还在运行呢?
这是因为Service和activity运行在同一个线程中,退出activity,但因为service还在,所以它所在的线程其实还是存在的。activity被销毁,只不过是这个activity所占用的资源被释放掉了,这个activity所在的主线程只有但android内存不足才会被杀掉,否则一般情况下activity所在的应用程序的线程始终存在,这也是这个activity所启动的服务会一直运行下去的原因。
Service和Thread的区别:
(总结一下下面这段话:就是Service可以一直在后台运行(不管activity退没退出),更方便于被各应用程序控制和管理)
Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以进行一些耗时的操作。
Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。
Service根据它启动方式的不同可以分为两种:启动型Service(无限生命)、绑定型Service(有限生命)。
- 启动型Service(无限生命)
如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。
如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。
当启动型Service被绑定:
如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。
- 绑定型Service(有限生命)
如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。
注意:
1、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;
2、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。
3、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。
一个Service例子:
在Manifest中注册:
<
application
. . . . . .
>
<
activity
. . . . . .
>
<
service
android:name
=
".
My
Service"
/>
</
application
>
public
class
MyService
extends
Service {
private
MyBinder
myBinder
=
new
MyBinder();
@Override
public
void
onCreate() {
//
只会在初次创建时调用一次
super
.onCreate();
}
@Override
public
int
onStartCommand(Intent intent,
int
flags,
int
startId) {
//
只有启动型Service会调用这个方法,startService方法可以被多次启动,同时此方法也会被多次调用
//
可以把启动型Service要做的任务写在这里,任务相关数据可以有intent传进来
return
super
.onStartCommand(intent, flags, startId);
}
@Override
public
IBinder onBind(Intent arg0) {
//
在Service被绑定时会调用
//
如果是绑定型Service,可以把相关数据通过Intent传进来
// return null;//
如果你是使用启动型Service,则返回null就可以了
return
myBinder
;
}
@Override
public
boolean
onUnbind(Intent intent) {
//
断开绑定
//
如果是绑定型Service,断开绑定/context连接消失/activity退出,都会使Service结束
//
如果是启动型Service,断开绑定,Service不会结束;断开绑定并且stopService服务才会结束
return
super
.onUnbind(intent);
}
@Override
public
void
onDestroy() {
// Service
结束,你可以在这里结束你创建的Thread或者一些变量
super
.onDestroy();
}
class
MyBinder
extends
Binder {
//
创建一个方法,返回本Service,这样前台就可以获得本Service实例,进行交互了
public
MyService getService() {
return
MyService.
this
;
}
}
}
启动此Service的几种方法:
- 启动型启动:
Intent intent=
new
Intent(MainActivity.
this
,
My
Service.
class
);
startService(intent);
stopService(intent);
//停止此service,intent不一定要用同一个实例
如果启动了Service后,需要绑定Service也可以,方法如下:
- 绑定型启动
public
class
MainActivity
extends
Activity {
private
Button
btn
_
StartService
;
private
Button
btn
_
StopService
;
private
BinderService
myService
;
private
Boolean
isConnected
=
false
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.
activity_main
);
btn
_
StartService
= (Button) findViewById(R.id.
btnStartService
);
btn
_
StopService
= (Button) findViewById(R.id.
btnStopService
);
btn
_
StartService
.setOnClickListener(
listener
);
btn
_
StopService
.setOnClickListener(
listener
);
}
private
OnClickListener
listener
=
new
OnClickListener() {
@Override
public
void
onClick(View v) {
switch
(v.getId()) {
case
R.id.
btnStartService
:
Intent intent =
new
Intent(MainActivity.
this
, BinderService.
class
);
//
绑定Service需要一个连接
bindService(intent,
conn
, Context.
BIND_AUTO_CREATE
);
break
;
case
R.id.
btnStopService
:
if
(
isConnected
) {
unbindService(
conn
);
}
break
;
default
:
break
;
}
}
};
private
ServiceConnection
conn
=
new
ServiceConnection() {
@Override
public
void
onServiceConnected(ComponentName name, IBinder binder) {
//
这里的参数binder就是Service的onBind()方法传进来的
//
这样就可以在这里获取到Service的实例,然后与Service进行交互
MyBinder myBinder = (MyBinder) binder;
myService
= myBinder.getService();
isConnected
=
true
;
}
@Override
public
void
onServiceDisconnected(ComponentName name) {
isConnected
=
false
;
}
};
}