What is a Service?
Most confusion about the Service class actually revolves around what it is
not:
- A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
- A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
Service不是一个进程,也不是一个线程,它运行在APP进程中的主线程中
Thus a Service itself is actually very simple, providing two main features:
- A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.
- A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.
Service是APP和系统沟通的一种方式:它告诉系统它想在后台做点事情。这个跟Context.startServie()相关,用来通知系统给Service安排工作,一直工作直到别的什么东东显示的停掉它。
APP暴露自己的某些功能给别的APP的一种方式。这个跟Context.bindService()相关,它为了和Service交互而保持长期的连接
When a Service component is actually created, for either of these reasons, all that the system actually does is instantiate the component and call its
onCreate() and any other appropriate callbacks on the main thread. It is up to the Service to implement these with the appropriate behavior, such as creating a secondary thread in which it does its work.
当Service组件创建出来后,系统要做的事情就是实例化组件,在主线程调用onCreate以及别的回调。Service需要自己实现这些函数的行为---比如创建一个worker thread。
Note that because Service itself is so simple, you can make your interaction with it as simple or complicated as you want: from treating it as a local Java object that you make direct method calls on (as illustrated by
Local Service Sample), to providing a full remoteable interface using AIDL.
你可以把Service看的很简单,也可以很复杂。简单的说,Service就是一个本地的Java对象,复杂的说,还可以是一个完全的远端AIDL接口。
如何创建Service?
Service Lifecycle
There are two reasons that a service can be run by the system. If someone calls
Context.startService() then the system will retrieve the service (creating it and calling its
onCreate() method if needed) and then call its
onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until
Context.stopService() or
stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their
stopSelf(int) method to ensure the service is not stopped until started intents have been processed.
系统有两种方式创建Service。某程序调用Context.startService时,系统会恢复service(调用onCreate创建它)并调用
onStartCommand方法。服务会一直运行直到Context.stopService或stopSelf被调到。另外,startService不是嵌套的,一个stopService下来,都被停止掉。
For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand():
START_STICKY is used for services that are explicitly started and stopped as needed, while
START_NOT_STICKY or
START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.
对于创建的service,有两个附加的主mode可以运行,基于onStartCommand的返回值:返回值是START_STRICKY用于显示的创建并停止的,START_NOT_STRICK或..用于仅保持运行来处理任何发给他们的命令的service。
Clients can also use
Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling
onCreate() while doing so), but does not call onStartCommand(). The client will receive the
IBinder object that the service returns from its
onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service's IBinder). Usually the IBinder returned is for a complex interface that has been
written in aidl.
客户端也能使用bindService来获取一个和Service的永久性连接。它同样创建了Service,但是木有调用onStartCommand。客户端将拿到IBinder(Service从onBind方法返回的),允许客户端能够有办法调用到Service。Service将保持运行直到连接不再建立---啥叫连接建立呢?就是client保留着对Service的IBinder的引用。
A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started
or there are one or more connections to it with the
Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's
onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
一个服务可以既被创建又有连接附着,在这种情况下,系统将会保持服务长期运行---从被创建开始,会有一个或多个连接附着在它身上(带BIND_AUTO_CREATE标志)。
一旦任何一个情况都不存在,service的onDestroy被调用,服务被终止。所有的打扫工作(停掉线程,反注册Receiver)都需要在onDestroy中做完。
简单的说,两种调用模式:
1. 组件调用模式,onCreate onStartCommand onDestroy
2. 绑定模式,onCreate onBind onUnBind onReBind onDestroy
几个service的例子:
public
class
DLService
extends
Service{
public
final
MyBinder
mBinder
=
new
MyBinder();
@Override
public
IBinder onBind(Intent intent) {
return
mBinder
;
}
public
class
MyBinder
extends
Binder{
public
DLService getService(){
return
DLService.
this
;
}
}
public
DLCenter
mDLCenter
;
@Override
public
void
onCreate() {
super
.onCreate();
mDLCenter
= DLCenterImp.getInstance(getApplicationContext());
}
@Override
public
void
onDestroy() {
super
.onDestroy();
mDLCenter
.stop();
}
public
void
addListener(DLListener listener){
mDLCenter
.addDLListener(DLListener.
TYPE_DOC
, listener);
}
public
void
removeListener(DLListener listener){
mDLCenter
.removeDLListener(DLListener.
TYPE_DOC
, listener);
}
public
void
addDocTask(DocItem item){
mDLCenter
.addDLDocTask(item);
}
public
void
cancelDocTask(DocItem item){
mDLCenter
.removeDLDocTask(item);
}
public
void
downloadAllDoc(List<DocItem> list){
mDLCenter
.changeDLDocTaskList(list);
}
}
context.startService的使用
MainTabActivity
startService(new Intent(getApplicationContext(), RcsService. class));
RcsService
public class RcsService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/* 此时必须执行这个函数*/
}
}
context.bindService的使用
public abstract boolean bindService (Intent service, ServiceConnection conn,
int flags);
public boolean bindService (Intent service, ServiceConnection conn, int flags, int userHandle) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
public abstract void
unbindService (ServiceConnection conn);
例子,文档下载:
在Service里
public class DLService extends Service{
public final MyBinder mBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder ;//传给调用Context.bindService的人一个IBinder子类对象,该对象含一个方法,可以返回Service的对象。也就是说,通过传回来一个IBinder,传回了Service的对象。
}
public class MyBinder extends Binder{
public DLService getService(){
return DLService. this ;
}
}
}
所以,在Activity里,
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
//这里需要StartService吗?
bindService( new Intent(this , DLService. class),
mConnection
,
Context. BIND_AUTO_CREATE );
}
private DLService mDownloadService;
private ServiceConnection
mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mDownloadService = ((DLService.MyBinder) service).getService();//这里拿到了Service的对象
}
public void onServiceDisconnected(ComponentName className) {
mDownloadService = null ;
}
};
@Override
public void onClick(View v) {
mDownloadService .downloadAllDoc(tmplist);//这里就随便用吧,这就是远程过程调用?RPC
}
因为Service也在主线程创建和运行,因此onStartCommand函数也会阻塞主线程,因此有两种方案去避免这一点:
1. 把Service放入独立的进程,如
<service android:name="simpleService" android:process=".a_unique_process_name">
但这样会增加一个进程
2. 在Service中另起一个线程
一个简单的策略是派生android.app.intentService类。它本身会启动一个后台线程