service基础

作为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的生命周期

service基础_第1张图片

发送通知(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
    }
}
 
    

service基础_第2张图片

0
0
猜你在找
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
快速回复 TOP

你可能感兴趣的:(service基础)