Android 学习笔记之——服务(service)

原文地址: http://www.cnblogs.com/jerry-lin300/archive/2011/12/15/2288818.html

作为android四大组件之一,Services主要用作后台的、耗时操作。它没有UI。应用程序的其他组件可以启动Service,此时Service 即会在后台持续运行,即使用户切换到了其他应用程序,service也依旧运行。此外,组件可以绑定一个Service,一般和它进行交换,甚至实现进程间通信(IPC)。一般:网络传输、播放音乐、执行文件I/O,或者和内容提供者(content provider)交互,都可以放到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的方法。
    这种方式须遵循以下步骤:
  1. 在Service中创建一个Binder的实例:
    • 包含Client可以调用的Public方法。
    • 返回当前Service的实例——也包含Client可以调用的Public方法。
    • 返回Service持有的其他类的的实例——也包含Client可以调用的Public方法。
  2. 在onBind()中返回Binder实例。
  3. 在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:
  1.     实现ServiceConnection:必须覆盖两个回调方法:
    • onServiceConnected()——系统调用这个方法来投递IBinder(从service的onBinder()方法返回)。
    • onServiceDisconnected()——当Client和Service之间的连接不是期望的丢失,例如Service崩溃,或者被杀死时,android系统调用这个方法。Client解绑定时,这个函数不会被调用。
  2. 调用bindService()。
  3. 在系统调用onServieConnected()时,就可以开始向通过调用定义的接口,呼叫Services。
  4. 调用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);
复制代码
     将一个Service从前台运行中移除,只需要调用stopForeground()。这个方法,有个boolean参数,表示是否也从状态栏移除通知。这个方法,并不停止service。然而,如果你停止了一个正在前台运行的service,那么它通知也将被移除。 
 
    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
}
}
复制代码


 

参考:

  1. android开发指南,http://developer.android.com/guide/topics/fundamentals/services.html
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值