Android service基础绑定一点通(绑定方法说明)

Service

 

   Service 是一个组件,用来执行长时间的后台操作,不提供用户界面

  另一个应用组件可以启动一个Service,它将持续地在后台运行,即便是用户转移到另一个应用它也不会停止。

  另外,Service可以和另一个组件绑定,与其进行交互,可以进行跨进程的通信(interprocess communication (IPC))。

  比如,Service可以用来处理网络交易,播放音乐,执行文件I/O,与content provider交互等,所有这些都是从后台进行。

 

一个Service可以采取两种形式

1.Started

  当另一个组件(比如一个activity)调用 startService()方法来启动一个service,这个service为started。

  一旦开始,这个service可以一直在后台运行,即便开启它的那个组件被销毁。

  通常,一个被开始的组件执行一个单一的操作,并不返回值给它的调用者。

  比如,它可以通过网络下载或上传一个文件。当这个操作完成时,service将自己停止。

 

2.Bound

  当另一个组件通过bindService()方法与其进行绑定,service就处于bound状态。

  一个被绑定的service提供一个client-service接口,允许组件和其进行交互,发送请求,得到结果,甚至进行跨进程的交互(interprocess communication,IPC)。

  一个被绑定的service只有当其他应用组件和其绑定的时候才运行。

  当多个组件与其绑定时,当所有组件都unbind时,这个service才被销毁。

 

  注意,service可以同时在这两种状态下工作,它可以被started(为了无限运行),同时允许绑定。

  仅仅关系到你是否实现了这两个回调函数:onStartCommand() 允许组件去开启它, onBind() 允许绑定。

  注意:一个service运行在其宿主进程的主线程里面。

  一个service不会创建它自己的线程,也不会运行在一个分开的进程里面(除非你特殊指定)。

  这意味着,如果你的service要做一些耗费CPU的工作或者阻塞性的操作(比如MP3播放或者网络操作),你应该在service里面创建一个新的线程去做这项工作

  通过一个独立的线程,你将减小遇到ANR(Application Not Responding)错误的风险,应用的主线程将能够继续保持用于在activity中和用户交互。

 

Service使用基础

  为了使用service,你必须创建一个继承自Service 的类。

 

最重要的几个要覆写的回调函数如下:

onStartCommand()

  当另一个组件,比如activity开启这个service时,开启动作是通过startService()方法,而service则会调用这个onStartCommand()函数。

  一旦这个onStartCommand()被执行,service将会在后台无限地运行,如果你要实现它,你需要在工作结束时停止这个service(通过stopSelf() 或  stopService())。

  当然,如果你只想提供绑定,你是不需要实现这个方法的。 

onBind()

  当另一个组件想要和service进行绑定时(绑定是通过bindService()方法),系统会调用这个onBind()方法。

  在你的实现中,你必须提供一个交互的接口IBinder。你必须实现这个方法,但是如果你不想允许绑定,你应该返回一个null。

  如果一个组件通过bindService()方法来创建一个service(并且onStartCommand() 没有被调用),那么这个service和创建它的组件有一样长的生命。

  一旦service和所有的客户组件解除绑定,系统将会销毁它。

onCreate()

  当service第一次被创建的时候系统会调用这个方法,如果这个service已经在运行,则不会调用这个方法。

onDestroy()

  当service不再被使用,被销毁时调用这个onDestroy()方法。

  你的service应该实现这个方法,去清理一些资源,比如线程、监听器、接收器等。这是一个service最后调用的方法。

 

在manifest中声明service

<application> 中增加一个 <service> 子标签:

复制代码
<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>
复制代码

 

  android:name 属性是唯一必须的属性,它指定了service的类名。

  更多信息可以看<service> 元素的文档。

  和activity一样,service中也可以定义intent filters,这样,其他组件就可以通过隐式的intent来启动这个service。这样,其他应用的组件就有可能开启你的service。

  如果你只想在你自己的应用中用这个service,你就不需要(也不应该)提供任何的intent filters。

  没有intent filters的service必须通过显式的intent来启动。

  另外,如果你想确保你的service是你的应用所私有的,你可以包含android:exported属性,将其设置为false。这样,即便是你的service提供了intent filters,别的应用中的组件也不能使用它。

 

 

 

Creating a Started Service

 

  一个被开始的service(started service)是另一个组件调用startService()开启的,结果是这个service的onStartCommand()方法被调用。

  当一个service被start,它就拥有一个独立于开始它的组件的生命周期,这个service可以无限地在后台运行,即使开始它的那个组件被销毁了。

  所以,service应该在完成工作后自己停止,通过调用stopSelf(),或另一个组件可以通过调用stopService()来停止它。

 

  简单说,就是: 

  一个应用组件,比如activity可以开启一个 service,通过调用startService() 方法并传递一个定制service和传递必要数据的intent对象。

  Service会在 onStartCommand()方法中获取这个对象。

 

  举个例子,一个activity需要把一些数据存储在一个网络上的数据库里,这个activity可以开启一个service,把要存储的数据通过一个startService()中的intent参数传递给service,service在 onStartCommand()方法中得到这个intent,建立网络连接并执行数据库事务。当事务处理完毕,service自己停止自己并销毁。

  注意:默认情况下,service运行在声明它的应用的同一个进程里面,而且在应用的主线程里面。

  所以,如果你的service需要执行一些繁重的或者阻塞性的工作,同时用户要和同一个应用中的activity进行交互,service会降低activity的性能。

  为了避免妨碍应用性能,你应该在service中新开启一个线程。

 

可以继承两个类去创建一个started service

Service

  这是所有service的基类。

  当你继承这个类时,比较重要的一点就是你需要创建一个新的线程,在里面做所有service的工作,因为这个service默认情况下会使用应用的主线程,这样会降低你的应用中正在运行的activity的性能。

 

IntentService

  这是一个Service类的子类,它使用一个工作线程(worker thread)来处理所有的开启请求,一次一个。

  如果你不要求你的service同时处理多个请求的话,这是你最好的选择。

  你需要做的仅仅是实现 onHandleIntent()方法,它将接收到每一个start请求的intent,所以你可以做后台的工作。

 

Extending the IntentService class

  因为多数的service不需要同时处理多个请求,所以你可以使用 IntentService来实现你自己的service。

  IntentService 做了如下的工作:

  1.创建一个默认的worker thread,与应用的主线程分离,处理所有传递给 onStartCommand()方法的intent。

  2.建立一个工作队列,一次传递一个intent给 onHandleIntent(),所以你永远不用担心多线程问题。

  3.当所有的start请求都被处理以后,停止service,所以你永远不必去调用 stopSelf()

  4.提供了onBind() 的默认实现,返回null。

  5.提供了 onStartCommand()的默认实现,把intent传向工作队列,然后传向 onHandleIntent() 的实现。

  所有的这些加起来,说明事实上你需要做的事情就仅仅是实现onHandleIntent()方法去做客户端提供的工作。

  当然,你还需要提供一个构造方法,它必须调用基类的IntentService(String)构造方法

 

  下面是一个实现例子:

复制代码
public class HelloIntentService extends IntentService 
{

  /** 
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() 
 {
      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
  protected void 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) 
         {
              }
          }
      }
  }
}
复制代码

 

  如果你决定覆写一些其他的回调方法,比如 onCreate()onStartCommand(), or onDestroy()请确定一定要调用基类的实现这样IntentService才能正确地管理worker线程的生命

  比如,onStartCommand() 必须返回默认的实现(这是有关intent被传递到 onHandleIntent()的)。

 

复制代码
@Override
public int onStartCommand(Intent intent, int flags, int startId) 
{
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
}
复制代码

 

  除了 onHandleIntent()还有仅一个方法中你不需要调用基类,那就是 onBind(),不过你仅仅在你的service允许绑定的时候需要实现它。

 

Extending the Service class

  如果你需要你的service去执行多线程,而不是通过一个工作队列处理开始请求,你可以继承Service 来处理每一个intent。

  为了比较,下面是一个继承了Service类的实现,做的工作和上面继承IntentService的完全相同:

直接继承Service类的实现

 

  可以看到,与使用IntentService相比,我们需要做更多的工作,但是,因为你自己处理onStartCommand()的每一次调用,所以你可以同时执行多个请求。

  这个例子没有这样做,如果你想要同时处理多个请求,你可以为每个请求创建一个新的线程,然后立即执行它们,而不是等待上一个请求执行完毕再执行。

 

  注意到onStartCommand()方法必须返回一个整形,这个整形描述了系统应该如何继续被系统kill掉的service,

  返回值必须是下列常量之一:

START_NOT_STICKY

  如果在 onStartCommand() 方法返回后系统将service销毁,不重建service,除非有pending intent被传递。

  这是最安全的一种选择,可以避免运行service在不必要的时候,和当你的应用可以重新开始未完成的工作的时候。

START_STICKY

  如果在 onStartCommand() 方法返回后系统将service销毁,重建service,并且调用onStartCommand()方法,但是不重新传递上一个intent

  系统调用 onStartCommand()方法时传递一个null intent。

  除非有pending intent来开启这个service,在这种情况下,pending intent是被传递的。

  这种情况对于多媒体播放器(或者其他类似的service)比较适合,它们不执行命令,但是它们等待工作并无限执行。

START_REDELIVER_INTENT

  如果在 onStartCommand() 方法返回后系统将service销毁,重建service,并且调用onStartCommand()方法,上一个intent将会被传递给service

  任何的pending intent将顺次被传递。

  这对于积极执行一项工作的service非常适合,因为它们应该被立即恢复,比如下载文件。

 

Starting a Service

  你可以从一个activity或其他组件通过startService()方法来开始一个service,需要传递一个Intent对象来指定要开启的service。

  Android系统会调用service的onStartCommand()方法然后把Intent对象传递给它。

  比如:

Intent intent = new Intent(this, HelloService.class);
startService(intent);

 

  startService() 方法会立即返回,Android系统会调用service的onStartCommand()方法,如果service不是已经在运行,那么系统会先调用它的 onCreate()方法,然后调用onStartCommand()

  如果service没有同时提供绑定,那么传递给startService() 方法的intent对象是调用组件和service之间唯一的交流形式。

  但是,如果你想要service发送一个结果回来,那么开启service的客户可以为broadcast创建一个PendingIntent,(用getBroadcast()方法),然后把它作为开启service的intent传给service。这个service之后就可以使用这个broadcast来传递一个结果。

  多次的开启请求会导致多次的onStartCommand()方法被调用,然而,只需要一个停止的请求 (with stopSelf() or stopService()) 就可以将service停止。

 

Stopping a service

  一个被开始的service必须管理自己的生命周期。

  即,系统不会停止或者销毁service(除非系统必须恢复一些内存),service将会在 onStartCommand() 方法返回之后一直持续运行。

  所以,service必须通过stopSelf()来停止自己,或者另一个组件通过stopService()来停止它。

  一旦通过 stopSelf() or stopService()方法发送了停止的请求,系统将会尽快销毁service。

 

  然而,如果你的service并行处理多个onStartCommand()请求,那么在你不应该在你处理完一个start请求之后stop这个service。因为你可能得到了一个新的start请求。(在第一个请求之后停止,有可能会终止第二个。)

  为了避免这个问题,你可以使用stopSelf(int) 来确保你要停止的请求永远基于最近开始的service。

  即是说,当你调用stopSelf(int) 时,你将start请求的ID  (the startId delivered toonStartCommand())传递过去。

  这样如果你的service在你的调用stopSelf(int)前得到一个新的start请求,由于ID不匹配,这个service不会被stop。

 

  注意:当service做完它的工作时,你的应用应该停掉它。这样可以避免系统资源浪费和电池能量消耗。

  如果有必要,其他组件可以通过stopService()来停止service。

  即便你允许绑定service,如果你的service有得到onStartCommand()方法的调用,你就永远必须自己停止它。








Creating a Bound Service

 

绑定Service的作用:

  一个绑定的service(bound service)是客户端-服务器接口中的服务器。

  绑定的service允许组件(比如activity)通过调用bindService()方法和其进行绑定,建立一个长期存在的连接关系,发送请求,接收回应,甚至执行跨进程的通信(interprocess communication (IPC))。

  当你需要从应用中的activity或者其他组件和service进行交互的时候,或者当你需要把应用中的一些功能通过跨进程的通信interprocess communication (IPC)暴露给其他的应用时,你应该建立一个绑定的service。

 

绑定Service的一般性实现:

  一个绑定的service是 Service类的一个实现,允许其他的组件和其进行绑定并交互。

  为了创建一个绑定的service,你必须做的第一件事是定义一个接口,指定客户如何和这个service进行交互。

  这个接口必须是IBinder接口的一个实现,并且是你的 onBind()回调方法返回的东西。

  所以,为了提供绑定,你首先必须实现onBind()回调方法,这个方法返回一个IBinder对象。

  其他组件可以调用bindService()方法来取得这个接口,然后就可以开始调用service中的方法。

  具体来说,一个客户端通过bindService()方法和service进行绑定。当客户端这样做的时候,它必须提供一个ServiceConnection的实现,用来监听和service之间的连接。 

  bindService()方法会立即返回,当Android系统创建了客户端和service之间的连接时,系统会调用ServiceConnection中的 onServiceConnected(),来传递 IBinder 对象,让客户端用来和service通信。

 

多个客户端绑定与生命周期的结束行为:

  一个service可以同时和多个客户端进行连接。

  但是,系统仅在第一次连接的时候调用service的onBind() 方法来获取IBinder对象。

  系统会将同一个IBinder对象传递给其他后来增加的客户端,不再调用onBind() 方法。

  

  当一个客户完成和service之间的互动后,它调用 unbindService() 方法来解除绑定。

  当所有的客户端都和service解除绑定后,系统会销毁service。(除非service也被startService()方法开启)。

  因为,通常情况下,一个绑定的service仅当它为其他组件服务时存在,所以当没有任何组件和其绑定时,系统会销毁它,不会在后台无限运行。你不需要去停止一个绑定的service。

 

  有很多方法来实现一个绑定的service,这个实现比开启的service要复杂。下面介绍三种方法。

 

Creating a Bound Service

  当创建一个提供绑定的service时,你必须提供给一个IBinder,来提供客户和service交互的接口。

  有三种方法可以定义这个接口:

 

1.继承Binder类

  如果你的service是你的应用所私有的,并且和客户端在同一个进程中运行,你应该通过继承Binder 类来创建接口,在 onBind()方法中返回它的实例。

  客户端接收到这个Binder对象,并且可以直接使用它来访问一些Binder甚至service中的public方法。

  当你的service仅仅是你的应用中的一个后台工作者时,这种方法是被推荐的。

  不使用这种方法创建接口的唯一理由就是你的service需要被其他应用使用,或者需要跨进程使用。

 

2.使用一个Messenger

  如果你需要你的接口跨进程使用,你可以使用 Messenger来创建接口。

  用这种方式,service定义一个 Handler用来响应不同类型的 Message 对象。

  这个Handler是 Messenger和客户分享一个 IBinder的基础,让客户端可以使用Message 对象向service发送命令。

  另外,客户端也可以定义自己的Messenger,这样service就可以发送信息给客户端。

  这是执行跨进程通信(interprocess communication (IPC))的最简单的方法,因为Messenger把所有的请求排列进一个单独的线程,所以你在设计service时不用为了线程安全而做特殊的设计。

 

3.使用AIDL

  AIDL (Android Interface Definition Language)执行分解对象的工作,它把对象分解成primitives,操作系统可以理解并将这些primitives跨进程分组(marshall)来执行IPC。

  前面使用Messenger的方法底层结构实际上是基于AIDL的。

  上面提到,Messenger在一个单独的线程中创建一个所有客户端请求的队列,所以service一次只接收一个请求。

  然而,如果你想要你的service同时处理多个请求,那么你可以直接使用AIDL。

  这种情况下,你的service必须能够处理多线程并且是线程安全的。

  要直接使用AIDL,你必须创建一个.aidl文件,定义编程接口。Android SDK使用这个文件来生成抽象类,实现接口和处理IPC,你可以在你的service中继承它。

  注意:多数应用不应该使用AIDL去创建一个bound service,因为它需要多线程,会导致一个复杂得多的实现。如果你确定要使用,可以查看 AIDL文档。

              

Android 绑定Service的实现方法一:扩展Binder类来构建接口

  

  接上文(Android Service的绑定 基础概念篇),绑定的service主要有三种不同的实现方法,在此介绍第一种方法。

 

Extending the Binder class

  如果你的service仅仅是被本应用所使用,不需要跨进程工作,那么你可以实现你自己的 Binder类,为客户端提供service中public方法的直接访问权限。

  注意:这种方法只适用于客户端和service在同一个应用的同一个进程中。

 

基本步骤

1.在你的service中,建立一个 Binder的实例,满足下列三个条件之一即可

  包含客户端可以调用的public方法。

  返回当前的service实例,其中含有public方法,客户端可以调用。

  返回service中一个其他类的实例,其中含有客户端可以调用的public方法。

 

2.在onBind()回调函数中返回这个Binder对象

3.在客户端中,通过onServiceConnected()回调函数接收这个Binder对象,之后就可以通过这个对象提供的方法来调用绑定的service中的方法。

 

程序例子

复制代码
public class LocalService extends Service
{
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();

    /**
     * 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.
     */
    public class LocalBinder extends Binder
    {
        LocalService getService()
        {
            // Return this instance of LocalService so clients can call public
            // methods
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return mBinder;
    }

    /** method for clients */
    public int getRandomNumber()
    {
        return mGenerator.nextInt(100);
    }
}
复制代码

 

  LocalBinder提供了getService()方法,这样客户端就可以获取LocalService当前的实例,进一步,客户端就可以调用public方法。

  比如,客户端可以调用getRandomNumber()方法。

  下面是一个activity,和LocalService进行了绑定,并且当按钮按下时会调用getRandomNumber()方法。

复制代码
public class BindingActivity extends Activity
{
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void 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)
     */
    public void 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() */
    private ServiceConnection mConnection = new ServiceConnection()
    {

        @Override
        public void 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
        public void onServiceDisconnected(ComponentName arg0)
        {
            mBound = false;
        }
    };
}
复制代码

 

  客户端是通过把ServiceConnection传递给 bindService()方法来进行绑定的。

  比如:

Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

 

   bindService()的第一个参数是一个intent,显示指定要绑定的service的名字,(这个intent也可以是隐式的);

  第二个参数是ServiceConnection对象;

  第三个参数是一个标志变量,作为绑定选项,它通常是BIND_AUTO_CREATE,为了在service不存在的情况下创建一个service。

  其他可能的选项是 BIND_DEBUG_UNBIND 和BIND_NOT_FOREGROUND,没有的话可以设置为0。

 

Android 绑定Service的实现方法二:使用Messenger

Using a Messenger

  

  接上文(Android Service的绑定 基础概念篇),绑定的service主要有三种不同的实现方法,在此介绍第二种方法。

  如果你需要你的service和其他进程通信,那么你可以使用一个Messenger来提供这个接口。

  这种方法允许你在不使用 AIDL的情况下,进行跨进程通信IPC。

 

实现步骤

  下面是一个如何使用 Messenger的小总结:

  1.service实现一个 Handler 接收客户端每一次调用的回调。

  2. Handler 用来创建一个Messenger对象,它是一个Handler的引用。

  3. Messenger创建一个 IBinderservice从 onBind()中把它返回给客户端。

  4.客户端使用这个IBinder来实例化Messenger (service的Handler的引用),客户端使用它来向service发送Message对象。

  5.service在它的Handler中接收每一个Message对象,在它的 handleMessage()方法中。

 

程序实例

  下面是一个使用Messenger接口的例子:

复制代码
public class MessengerService extends Service
{
    /** Command to the service to display a message */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler
    {
        @Override
        public void 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.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * When binding to the service, we return an interface to our messenger for
     * sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent)
    {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT)
                .show();
        return mMessenger.getBinder();
    }
}
复制代码


  注意 Handler中的 handleMessage() 方法是service接收到来的 Message并且决定做什么的地方。

  客户端需要做的仅仅是创建一个基于service所返回的 IBinder的 Messenger,然后用 send()方法发送信息。

  比如,这里有一个简单的activity和service绑定并且发送信息给service:

复制代码
public class ActivityMessenger extends Activity
{
    /** 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.
     */
    private ServiceConnection mConnection = new ServiceConnection()
    {
        public void 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 = new Messenger(service);
            mBound = true;
        }

        public void 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;
        }
    };

    public void 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
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
                Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        // Unbind from the service
        if (mBound)
        {
            unbindService(mConnection);
            mBound = false;
        }
    }
}
复制代码

 

  注意这个例子并没有展示service如何响应客户端,如果你想要service响应,你需要在客户端中创建一个 Messenger

  然后当客户端接收到onServiceConnected()回调方法时,它会发送一个 Message到service,在它的send() 方法的replyTo参数中包含了客户端的Messenger。

 

Android Service的绑定 续篇:关于绑定的补充说明

  

 

Binding to a Service

  应用组件(客户端)可以通过 bindService()方法绑定到service,Android系统随后会调用service的 onBind()方法,返回一个 IBinder 用于和service交互。

  绑定过程是异步的(asynchronous) , bindService()方法会立即返回,但是不会返回IBinder对象给客户端。

  为了接收到IBinder,客户端必须创建一个ServiceConnection的实例,并且把它传给 bindService(),这个 ServiceConnection中会包含一个回调函数,系统调用它来传递 IBinder对象。

 

  注意:仅仅是activity,service和content provider可以和service绑定,你不能把一个broadcast receiver和一个service绑定。

 

为了将客户端和service绑定,你必须:

1.实现ServiceConnection

  其中需要实现两个回调方法:

  onServiceConnected()

  系统调用这个方法来传递service的onBind()方法返回的 IBinder 。

  onServiceDisconnected()

  当和service的连接意外丢失时,系统会调用这个方法。如果是客户端解除绑定,系统不会调用这个方法。

2.调用 bindService(),并传递 ServiceConnection的实现。

3.当系统调用你的 onServiceConnected(),你可以开始用接口定义的方法访问service。

4.要断开连接,调用 unbindService()

  当你的客户端被销毁的时候,会断开与service的连接,但是你应该在停止与service的交互时断开连接或者当activity暂停时断开连接,这样service就可以在它不被使用的时候关闭。

 

Additional notes

  1.注意 DeadObjectException 异常,它会在连接断开时被抛出。

  2.对象是整个进程计数的引用。(Objects are reference counted across processes.)

  3.绑定和解除绑定应该在客户端生命周期中建立和销毁的对等时间执行。

  比如:

  如果你只需要在activity可见的时候和service交互,你应该在onStart()绑定,在 onStop()中解除绑定。

  如果你想要你的activity即便在后台停止时仍然接收响应,你可以在onCreate()中绑定,在onDestroy()中解除绑定。

 

  通常不在 onResume() 和 onPause()方法中进行绑定和解除绑定,因为这些回调函数在每次生命周期转换的时候都会调用,你应该把这些转换中的操作保持到最小。并且,如果多个activity绑定到同一个service,并且其中的两个activity有一个转换,service可能会被销毁然后又被重建。




Android Service的生命周期

Managing the Lifecycle of a Service

  service的生命周期,从它被创建开始,到它被销毁为止,可以有两条不同的路径:

A started service

  被开启的service通过其他组件调用 startService()被创建。

  这种service可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它。

  当service被停止时,系统会销毁它。

 

A bound service

  被绑定的service是当其他组件(一个客户)调用bindService()来创建的。

  客户可以通过一个IBinder接口和service进行通信。

  客户可以通过 unbindService()方法来关闭这种连接。

  一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。

 

  这两条路径并不是完全分开的。

  即是说,你可以和一个已经调用了 startService()而被开启的service进行绑定。

  比如,一个后台音乐service可能因调用 startService()方法而被开启了,稍后,可能用户想要控制播放器或者得到一些当前歌曲的信息,可以通过bindService()将一个activity和service绑定。这种情况下,stopService()或 stopSelf()实际上并不能停止这个service,除非所有的客户都解除绑定。

 

Implementing the lifecycle callbacks

  和activity一样,service也有一系列的生命周期回调函数,你可以实现它们来监测service状态的变化,并且在适当的时候执行适当的工作。

  下面的service展示了每一个生命周期的方法:

复制代码
public class ExampleService extends Service
{
    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
    public void onCreate()
    {
        // The service is being created
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        // A client is binding to the service with bindService()
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent)
    {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }

    @Override
    public void onRebind(Intent intent)
    {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    @Override
    public void onDestroy()
    {
        // The service is no longer used and is being destroyed
    }
}
复制代码

 

  不像是activity的生命周期回调函数,你不需要调用基类的实现。

 

  这个图说明了service典型的回调方法,尽管这个图中将开启的service和绑定的service分开,但是你需要记住,任何service都潜在地允许绑定。

  所以,一个被开启的service仍然可能被绑定。

  实现这些方法,你可以看到两层嵌套的service的生命周期:

 

The entire lifetime

  service整体的生命时间是从onCreate()被调用开始,到onDestroy()方法返回为止。

  和activity一样,service在onCreate()中进行它的初始化工作,在onDestroy()中释放残留的资源。

  比如,一个音乐播放service可以在onCreate()中创建播放音乐的线程,在onDestory()中停止这个线程。

   onCreate() 和 onDestroy()会被所有的service调用,不论service是通过startService()还是bindService()建立。

 

The active lifetime

  service积极活动的生命时间(active lifetime)是从onStartCommand() 或onBind()被调用开始,它们各自处理由startService()或 bindService()方法传过来的Intent对象。

  如果service是被开启的,那么它的活动生命周期和整个生命周期一同结束。

  如果service是被绑定的,它们它的活动生命周期是在onUnbind()方法返回后结束。

  注意:尽管一个被开启的service是通过调用 stopSelf() 或 stopService()来停止的,没有一个对应的回调函数与之对应,即没有onStop()回调方法。所以,当调用了停止的方法,除非这个service和客户组件绑定,否则系统将会直接销毁它,onDestory()方法会被调用,并且是这个时候唯一会被调用的回调方法。

 

Managing the Lifecycle of a Bound Service

  当绑定service和所有客户端解除绑定之后,Android系统将会销毁它,(除非它同时被onStartCommand()方法开启)。

  因此,如果你的service是一个纯粹的绑定service,那么你不需要管理它的生命周期

  然而,如果你选择实现onStartCommand()回调方法,那么你必须显式地停止service,因为service此时被看做是开启的。

  这种情况下,service会一直运行到它自己调用 stopSelf()或另一个组件调用stopService(),不论它是否和客户端绑定。

  另外,如果你的service被开启并且接受绑定,那么当系统调用你的 onUnbind()方法时,如果你想要在下次客户端绑定的时候接受一个onRebind()的调用(而不是调用 onBind()),你可以选择在 onUnbind()中返回true。

  onRebind()的返回值为void,但是客户端仍然在它的 onServiceConnected()回调方法中得到 IBinder 对象。

  下图展示了这种service(被开启,还允许绑定)的生命周期:

 

参考资料

  API Guides:Services

  http://developer.android.com/guide/components/services.html

  API Guides:Bound Services

  http://developer.android.com/guide/components/bound-services.html


参考资料

  API Guides:Bound Services

  http://developer.android.com/guide/components/bound-services.html


参考资料         

  API Guides:Services

  http://developer.android.com/guide/components/services.html

  API Guides:Bound Services

  http://developer.android.com/guide/components/bound-services.html




参考资料

  API Guides:Services

  http://developer.android.com/guide/components/services.html

  API Guides:Bound Services

  http://developer.android.com/guide/components/bound-services.html

  博客园博客:

  http://www.cnblogs.com/feisky/archive/2010/06/14/1758336.html

  CSDN 博文:

  http://blog.csdn.net/fengqiangfeng/article/details/7555213

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值