作为android四大组件之一,Services主要用作后台的、耗时操作。它没有UI。应用程序的其他组件可以启动Service,此时Service 即会在后台持续运行,即使用户切换到了其他应用程序,service也依旧运行。此外,组件可以绑定一个Service,一般和它进行交换,甚至实现进程间通信(IPC)。一般:网络传输、播放音乐、执行文件I/O,或者和内容提供者(content provider)交互,都可以放到Service中到后台来执行。
我们知道,在创建一个Bound Service时,必须一个IBinder接口以供Client和Service交互、通信。有三种方式可以用来定义这样的一个接口:
将一个Service从前台运行中移除,只需要调用stopForeground()。这个方法,有个boolean参数,表示是否也从状态栏移除通知。这个方法,并不停止service。然而,如果你停止了一个正在前台运行的service,那么它通知也将被移除。
之前已经提到,Service可以被启动,也可以被绑定。不难理解,Service的两种形式:started Service和bound Service。
- started:这是一种被应用的组件以调用startService()方法的方式启动的Service。这种Service,被启动后,就开始独立运行,即便当初启动它的组件被摧毁了,也依旧工作。通常,一个started Service执行单独的、不需向调用者返回结果的操作。当操作完成以后,服务应该结束自己。例如,通过网络上传、下载一个文件。
- bound:这是一种被应用的组件以调用bindService()方法的方式启动的service。这种Service,提供一种Client-Server的接口,来允许组件和Service进行交互:发送请求、获取结果,甚至以这种方式实现夸进程的IPC。bound Service的生命周期依赖于绑定它的组件,和绑定它的组件的生命周期一致。当绑定它的组件的生命周期结束时,bound Service的生命周期也结束。bound Service可以被多个组件绑定,此时,只有多有和它绑定的组件和它unbind之后,这个Service才被摧毁。
- 混合模式:一个Service可以同时是started、bound模式,Service支持同时是started、bound的方式。
看上去Service和Thread很像,那么什么时候使用Service,什么时候使用Thread?一般,如果不需要和用户交互也需要执行的任务可以选择使用Service,如果任务只在用户交互驱动时,才工作的,而又不想在main线程中执行,可以选择使用Thread。
不管是哪种模式的Service,任何一个应用的组件都可以以一种相同的方式使用一个Service,——以Intent来启动。当然,也可以在manifest中声明为私有,阻止来自其他程序的访问。
service 基础
为了创建一个Service,必须创建一个继承自Service或者它的子类的类。在实现中,需要重载一些回调方法来处理Service生命周期的关键环节,以及为组件绑定该Service提供一种合适的机制。下面是一些在创建的类中,需要实现的最重要的回调方法:
- onStartCommand(): 其他组件调用startService()来启动一个Service时,系统会调用这个回调函数,该函数执行过后,Service就已经被启动了,并且开始在后独立运行。如果你实现了这个函数,那么就必须由你来停止Service,要么调用stopSelt(),要么调用stopService()。也就是说,如果Service只是向提供绑定服务,那么就不需要实现这个方法。让其使用系统默认的实现。
- onBind(): 其他组件调用bindService()来绑定一个Service时,系统会调用这个回调函数。在实现这个方法(onBind())时,必须提供一个可供Client和Service通信的接口,该接口通过返回一个IBinde来传递。如果不允许service被绑定,那么这里返回null, 否则必须实现这个接口。
- onCreate(): 系统在Service第一次被创建的时候调用该方法,它是再onStartCommand()和onBind()方法之前被调用的。如果这个Service已经在运行了,那么这个函数不会被调用。
- onDestroy():系统在一个Service不再被使用,并且准备摧毁的时候调用该方法,它是Service收到的最后一个被调用的方法。在这里可以进行一些清除工作,例如线程、注册的监听、以及接收器等等。
一个被startService()方法启动的Service,它将会一直运行,直到自己调用了stopSelf(),或者其他组件调用了stopService()。
一个被bindService()犯法启动的Service,它的生命周期和绑定在它上面的组件一样。一旦所有绑定其的client都解绑定了,系统就会摧毁这个Service。
android系统只有在内存不足时,并且必须为拥有焦点的activity回收资源时,强制停止一个Service。如果一个service绑定到了一个拥有焦点的activity上,那么它被杀死的几率比普通的更低。而如果一个Service被声明为在前台运行,那它几乎不可能被杀死。然而如果,一个仅仅只是长期运行的long-running Service,系统将它的位置设置地比后台任务低好几倍,并且这种Service很容易被杀死,你必须优雅地设计这种Service,以便处理其被系统重新启动的情况。
要使用一个service, 首先需要类似activity那样在manifest中声明service。如:
<manifest...> ... <application> <service android:name=".ExampleService" /> ... </application> </manifest>
如果不希望被其他应用使用,则只须不声明 intent filter.如何这么做,那只能显示地调用Service类名。此外,可以设置android:exported,为false,来设置Service为你的应用所私有的。
创建一个started service
started service是一个由其它组件通过调用startService()方法启动的Service,并且这种方式将导致系统调用onStartCommand()方法(如果目标机是1.6或者1.6以前的话,则要以onStart()。2.0以后onStart()被废弃)。
其它组件通过Intent指定Service,并且包含一些供Service使用的数据。Service通过onStartCommand()接收Intent。
由于started Service的生命周期独立于启动它的组件,所以在其任务完成时,需要调用stopself()或者其它组件调用stopService()。
需要注意的是,Service是运行在声明它的应用程序的进程中,并且默认运行在主线程中。所以如果Service执行一些密集的、阻塞型的操作,它将会是activity和用户的交互变慢,为了避免影响应用程序的性能,应该在Service中启动一个新的线程。
有两个类可以用来扩展、继承以创建一个新的Service:
- Service:这是所有Service的基类。当使用这个类时,在Service中创建一个线程来实现Service的所有工作,是非常重要的(因为之前已经提到,默认情况下,Service运行在程序的主线程中)。
- IntentService:这是Service的一个子类,它使用一个工作线程来处理所有的启动请求,每次执行一个请求。如果你不需要一个Service同时处理多个请求,这是一个最好的选择。使用这这个类时,所有需要做的,仅仅只是实现onHandleIntent(),来处理请求。
继承、扩展IntentService类
IntentService做了以下工作:
- 创建一个默认的工作线程,来处理从应用程序主线程投递到onStartCommand()的Intent。
- 创建一个队列,它每次向onHandleIntent()传递一个Intent,这样就不需要关心多线程的同步问题。
- 在所有启动请求都被处理之后,自动停止Service,这样开发人员就不需要调用stopSelf()。
- 提供了默认的onBind()实现,它返回null。
- 提供了默认的onStartCommand()实现,它将intent发送到工作队列中,然后工作队列再讲intent发送到onHandleIntent()。
以上所有都表明,开发人员只需要实现onHandleIntent()方法,例如:
publicclassHelloIntentServiceextendsIntentService{ /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. */ publicHelloIntentService(){ super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protectedvoid onHandleIntent(Intent intent){ // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime =System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()< endTime){ synchronized(this){ try{ wait(endTime -System.currentTimeMillis()); }catch(Exception e){ } } } } }
例中所有需要开发者做的就是,实现Service的构造函数和onHandleIntent()。
如果你决定要覆盖其他的回调函数,那么要保证调用超类的中的实现。例如onStartCommand()必须返回默认的实现:
@Override publicint onStartCommand(Intent intent,int flags,int startId){ Toast.makeText(this,"service starting",Toast.LENGTH_SHORT).show(); returnsuper.onStartCommand(intent,flags,startId); }
继承、扩展Service类
当需要Service实现多线程并发的请求时,应该从Service类扩展,来处理每一个Intent。例如:
publicclassHelloServiceextendsService{ privateLooper mServiceLooper; privateServiceHandler mServiceHandler; // Handler that receives messages from the thread privatefinalclassServiceHandlerextendsHandler{ publicServiceHandler(Looper looper){ super(looper); } @Override publicvoid handleMessage(Message msg){ // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime =System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()< endTime){ synchronized(this){ try{ wait(endTime -System.currentTimeMillis()); }catch(Exception e){ } } } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override publicvoid onCreate(){ // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread =newHandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler =newServiceHandler(mServiceLooper); } @Override publicint onStartCommand(Intent intent,int flags,int startId){ Toast.makeText(this,"service starting",Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override publicIBinder onBind(Intent intent){ // We don't provide binding, so return null return null; } @Override publicvoid onDestroy(){ Toast.makeText(this,"service done",Toast.LENGTH_SHORT).show(); } }
这个例子中,为每一个启动请求,都启动一个工作线程来完成这项共工作,每次只处理一个请求。由于开发者实现了onStartCommand(),所以可以并发的执行多个请求。如果有需求,可以为每个请求启动一个线程,然后使它们正确地运行。
onStartCommand()必须返回一个整数,这个整数,告诉系统,如何继续这个Service,当系统杀死这个Service的时候。onStartCommand()的返回值,必须是以下几个:
- START_NOT_STICKY,如果系统在onStartCommand()之后杀死了Service,除非有待投递的Intent,否则不要在重新创建Service。这是一个安全的选项,使得 能够避免在不需要的时候运行Service,并且能够简单地重启那些未完成的工作。
- START_STICKY,重启Service,并且重新调用onStartCommand(),但是不要再次投送最后一个Intent。取而代之的是,系统调用onStartCommand(),并且,除非Service中还有其它待投递的Intent,否则向它传递null Intent。这种情形适合Media players——未在执行命令的,并且无限期的运行、等待工作的媒体播放器。
- START_REDELIVER_INTENT,重新创建Service,并且传递最近的一个Intent。其它待投递的Intent有序的跟着被投递。这种情形适合那些积极的执行那种必须马上恢复工作的Service,例如下载文件。
启动一个Service
activity或者应用程序的其他组件,可以通过向startSerive()传递一个Intent来启动一个Service,系统调用Service的回调函数onStartCommand(),并且向其传递这个Intent。例如:
Intent intent =newIntent(this,HelloService.class); startService(intent);如果该Intent还未运行,那么系统会先调用onCreate(),然后调用onStartCommand()。
如果Service不提供绑定。通过startService()投递Intent是应用组件和Service唯一的通信方式。然而,如果你希望Service发回结果,那么启动该Service的Client可以为广播(getBroadcast())创建一个待定的Intent(PendingIntent),并且随Intent一起通过startService()投递,然后Service可以使用这个广播来返回结果。
多个请求要启动Service,导致了系统对应地调用onStartCommand(),然而,想要停止一个Service,只需要一个请求(stopSelf()或者stopService())。
停止一个Service
一个Started的Service,必须自己管理生命周期,因为,除非系统为了回收内存,否则不会停止或者摧毁这样的Service,并且即便因为回收内存而摧毁了这样的Service,也会在onStartCommand()返回后继续运行。所以必须调用stopSelf()或者被其他组件调用stopService(),来终止一个Service。
一旦调用了stopSelf()或者stopService(),系统将在尽可能快的时间里终止Service。
然而,如果你的Service正在处理多个请求,那么就不能终止请求,因为有可能接收到了多个启动请求(在第一个请求的结尾结束,可能导致终止第二个请求)。为了避免这种情况,可以使用stopSelf(int),来保证停止Service的请求是基于最近的请求。这是因为,当调用stopSelf(int)时,你传递了对应的要停止的请求的启动请求的ID(statedID被投递到onStartCommand()),然后如果在你调用stopSelf(int)之前收到了一个新的请求,那么这两个ID将不会匹配,此时Service就不会被停止。
创建一个Bound Service
一个Bound Service允许应用程序的其它组件调用bindService(),以创建一个长期的存在的连接(并且一般不允许组件通过调用startService()来启动它)。
当你需要同过IPC让应用程序的组件(activity和其它组件)和Service进行交互的时候,或者想要将应用中的一些功能暴露给其它应用程序的时候,应该创建一个bound service。为了创建Bound Service,必须实现onBind()回调方法,它返回一个IBinder——它定义了和Service交互的接口。其它应用的组件可以调用bindService()来接收这个接口,并且开始调用在Service上的方法。这种Service只在应用程序的组件绑定它的时候才存活。所以当没有组件和Service绑定的时候,系统将摧毁这个Service。
为了创建一个Bound Service,必须首先定义指定Client和Service如何交互、通信的接口。Client和Service直接的接口必须是一个IBinder,也就是Service中onBind()回调必须要返回的IBinder。Client接收到IBinder之后,就可以和Service交互了。
有多个Client可以绑定到一个Service上,Client调用unbindService()来解绑定,如之前提到过的,一点一个Service没有Client绑定到它上面时,系统将会摧毁它。
我们知道,在创建一个Bound Service时,必须一个IBinder接口以供Client和Service交互、通信。有三种方式可以用来定义这样的一个接口:
- 扩展Binder类(Extending the Binder class):如果Service是你的程序所私有的,并且和Client允许在同一个进程中,你应该通过扩展Binder类来创建接口,并且从onBinde()返回它的实例。Client接收到以后,通过它直接访问Binder中、或者Service中的Public方法。当服务是你的程序私有的时候,这是首选的一项技术。不能以这个方式创建接口的唯一理由是,Service要被其他程序所用,或者需要跨进程使用。
- 使用一个Messenger(Using a Messenger):如果需要接口能够在跨进程间使用,可以以一个Messenger创建接口,这种方式,Service定义一个Handler来响应各种不同的Message对象。这个Handler是Messager和Client共享一个IBinder的基础,它允许Client使用Message对象向Service发送命令。并且Client也可以定义一个Messenger,这样Service可以向Client发送Messages。这是一种简单的IPC,因为Messenger队列要求是个单线程的,这样就不许要为线程安全而设计Service。
- 使用AIDL(Using AID):AIDL(ANDROID INTERFACE DEFINITION LANGUAGE)执行所有工作——将对象分解成系统能理解的原语,并且使它们能够跨进程执行。使用Messenger的方式,实际是就是基于AIDL的。和Messenger方式不同的是,Messenger方式,在一个单独的线程中创建所有请求的队列,所以这样的Service每次只能接收一个请求。而如果需要Service并发地处理请求,那就可以直接使用AIDL来实现,此时,Service必须具备多线程能力,并且要线程安全的。
为了能够直接使用AIDL,必须创建一个.adil文件,它定义了程序的接口。android sdk tool用这个文件来生成抽象类——实现interface和处理IPC,然后在Service中继承、扩展它。
继承、扩展Binder类
如果Service只在本地程序工作,并且不考虑跨进程,那么就可以通过这种继承、扩展Binder类来实现,它使Client直接访问Service中Public的方法。
这种方式须遵循以下步骤:
- 在Service中创建一个Binder的实例:
- 包含Client可以调用的Public方法。
- 返回当前Service的实例——也包含Client可以调用的Public方法。
- 返回Service持有的其他类的的实例——也包含Client可以调用的Public方法。
- 在onBind()中返回Binder实例。
- 在Client侧,从onServiceConnected()回调方法中接收这个Binder,并且使用Binder包含的Service提供的方法。
publicclassLocalServiceextendsService{ // Binder given to clients privatefinalIBinder mBinder =newLocalBinder(); // Random number generator privatefinalRandom mGenerator =newRandom(); /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ publicclassLocalBinderextendsBinder{ LocalService getService(){ // Return this instance of LocalService so clients can call public methods returnLocalService.this; } } @Override publicIBinder onBind(Intent intent){ return mBinder; } /** method for clients */ publicint getRandomNumber(){ return mGenerator.nextInt(100); } } publicclassBindingActivityextendsActivity{ LocalService mService; boolean mBound =false; @Override protectedvoid onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protectedvoid onStart(){ super.onStart(); // Bind to LocalService Intent intent =newIntent(this,LocalService.class); bindService(intent, mConnection,Context.BIND_AUTO_CREATE); } @Override protectedvoid onStop(){ super.onStop(); // Unbind from the service if(mBound){ unbindService(mConnection); mBound =false; } } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ publicvoid onButtonClick(View v){ if(mBound){ // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this,"number: "+ num,Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ privateServiceConnection mConnection =newServiceConnection(){ @Override publicvoid onServiceConnected(ComponentName className, IBinder service){ // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder =(LocalBinder) service; mService = binder.getService(); mBound =true; } @Override publicvoid onServiceDisconnected(ComponentName arg0){ mBound =false; } }; }
使用一个Messenger
如果需要Service能够和远端进程通信,可以是哟一个Messenger提供Service的接口,这项技术允许执行IPC,而不需要用AIDL。
- Service实现一个Handler——用来接收来自Client的回调。
- 这个Handler用来创建一个Messenger对象——一个Hnadler的引用。
- Messenger创建一个IBinder——由onBind()返回。
- Client使用IBinder来实例化Messenger(—一个Hnadler的引用),Client通过这个Messenger向Service发送Message对象。
- Service在它的Handler中接收每一个Message。
这种方式,Client以向Service投递消息替代调用Service的Public方法。
publicclassMessengerServiceextendsService{ /** Command to the service to display a message */ staticfinalint MSG_SAY_HELLO =1; /** * Handler of incoming messages from clients. */ classIncomingHandlerextendsHandler{ @Override publicvoid handleMessage(Message msg){ switch(msg.what){ case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(),"hello!",Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ finalMessenger mMessenger =newMessenger(newIncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override publicIBinder onBind(Intent intent){ Toast.makeText(getApplicationContext(),"binding",Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } } publicclassActivityMessengerextendsActivity{ /** Messenger for communicating with the service. */ Messenger mService =null; /** Flag indicating whether we have called bind on the service. */ boolean mBound; /** * Class for interacting with the main interface of the service. */ privateServiceConnection mConnection =newServiceConnection(){ publicvoid onServiceConnected(ComponentName className,IBinder service){ // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService =newMessenger(service); mBound =true; } publicvoid onServiceDisconnected(ComponentName className){ // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService =null; mBound =false; } }; publicvoid sayHello(View v){ if(!mBound)return; // Create and send a message to the service, using a supported 'what' value Message msg =Message.obtain(null,MessengerService.MSG_SAY_HELLO,0,0); try{ mService.send(msg); }catch(RemoteException e){ e.printStackTrace(); } } @Override protectedvoid onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protectedvoid onStart(){ super.onStart(); // Bind to the service bindService(newIntent(this,MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protectedvoid onStop(){ super.onStop(); // Unbind from the service if(mBound){ unbindService(mConnection); mBound =false; } } }
绑定到一个Service
应用程序的通过bindService()绑定到一个Service。Android系统调用Service的onBind(),它返回IBinder,以便Client和Service交互。
注意:只有activities、services和content providers可以绑定到一个Service,不能从broadcast receiver绑定一个service。
从Client绑定一个Service:
- 实现ServiceConnection:必须覆盖两个回调方法:
- onServiceConnected()——系统调用这个方法来投递IBinder(从service的onBinder()方法返回)。
- onServiceDisconnected()——当Client和Service之间的连接不是期望的丢失,例如Service崩溃,或者被杀死时,android系统调用这个方法。Client解绑定时,这个函数不会被调用。
- 调用bindService()。
- 在系统调用onServieConnected()时,就可以开始向通过调用定义的接口,呼叫Services。
- 调用unbindService()来断开Service。当Client被摧毁时,它会和Service解绑定。但是在和服务完成交互时、或者你的activity pause时,你必须解绑定,这样Service在不被使用才能被关闭。
例子:
LocalService mService; privateServiceConnection mConnection =newServiceConnection(){ // Called when the connection with the service is established publicvoid onServiceConnected(ComponentName className,IBinder service){ // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder =(LocalBinder) service; mService = binder.getService(); mBound =true; } // Called when the connection with the service disconnects unexpectedly publicvoid onServiceDisconnected(ComponentName className){ Log.e(TAG,"onServiceDisconnected"); mBound =false; } }; Intent intent =newIntent(this,LocalService.class); bindService(intent, mConnection,Context.BIND_AUTO_CREATE);
绑定一个Service时所需要注意的:
- 必须处理DeadObjectException异常。
- Object是夸进程的引用计数
- 在Client生命周期中——启动、停止,成对的使用绑定和解绑定。
- 如果只是在Activity可见时才和Service交互,那么应该在onStart()时绑定,onStop()时解绑定。
- 如果想要Activity即使在后台运行,stop状态,也要和Service交互,那么就应该在onCreate()时绑定,onDestroy()时解绑定。需要注意的是。这种情形,在Activity的整个生命周期中都要使用Service,此时如果Service是运行在其他进程中,那么你就加重了该进程,并且它也变得更容易被系统杀死。
- 一般不要在onResume()和onPause()中进行绑定和解绑定。
Bound Service的生命周期
发送通知(Notification)给用户
Service可以通过Toast Notification或者Status Bar Notification通知用户。
- Toast Notification:是一种现实在当前窗口,并且过一段时间后就消失的消息。
- Status Bar Notification:是一种在状态栏提供icon的消息,用户可以选择它,以启动一种动作(例如:启动一个activity)。
详见《开发指南》用户接口中的通知章节。
运行一个前台Service
一个前台运行的Service,是一个用户知道的,当系统内存不足时,并不会选择杀死这样的Service来回收内存。一个前台Service必须提供一个status bar的通知,它被放在Ongoing头下——表示不能被dismissed,除非这个服务停止了或者被从前台服务移除了。
例如,一个音乐播放器,从一个Service播放音乐,需要被设置成前台运行,因为用户明显地知道它的操作。status bar中可能代表着当前的歌曲,并且允许用户启动一个activity来和播放器交互。
调用startForegound()来使你的Service运行在前台。这个方法有两个参数,一个整数代表通知的唯一的ID,一个是status bar的通知:
Notification notification =newNotification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis()); Intent notificationIntent =newIntent(this,ExampleActivity.class); PendingIntent pendingIntent =PendingIntent.getActivity(this,0, notificationIntent,0); notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent); startForeground(ONGOING_NOTIFICATION, notification);
android 2.0 之后才能使用上述两个接口,如果在更早的版本,那需要使用setFroeground()。
管理一个服务的生命周期
Service的生命周期有两种方式:
- started service:当其他组件调用startService(),开始,当调用stopSelf(),或者stopService()结束,当服务停止时,系统将摧毁它。
- bound service:当其他组件调用bindService(),开始,client和service通过IBinder接口通信,当client调用unbindService()。
这两种模式,并不是完全独立的,因为一个已经started 的Service可以被bind。当这种情形出现时,一个stopSelf()、stopService()并不能时Service停止,只有Client也调用了unbind()之后,Service才被停止。
publicclassExampleServiceextendsService{ int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for clients that bind boolean mAllowRebind;// indicates whether onRebind should be used @Override publicvoidonCreate(){ // The service is being created } @Override publicintonStartCommand(Intent intent,int flags,int startId){ // The service is starting, due to a call to startService() returnmStartMode; } @Override publicIBinderonBind(Intent intent){ // A client is binding to the service with bindService() returnmBinder; } @Override publicbooleanonUnbind(Intent intent){ // All clients have unbound with unbindService() returnmAllowRebind; } @Override publicvoidonRebind(Intent intent){ // A client is binding to the service with bindService(), // after onUnbind() has already been called } @Override publicvoidonDestroy(){ // The service is no longer used and is being destroyed } }