Bound service

A bound service is the server in a client-server interface. A bound service allows components(such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves anotherapplication component and does not run in the background indefinitely.

This document shows you how to create a bound service, including how to bindto the service from other application components. However, you should also refer to theServices document for additionalinformation about services in general, such as how to deliver notifications from a service, setthe service to run in the foreground, and more.

一个绑定的服务是服务客户-服务 接口,一个绑定的服务允许组件(例如activity)去绑定服务,发送请求,接受命令,甚至处理进程间通信。一个绑定的服务通常依附于它所服务的组件 而不会无限期的在后台运行。

   这个文档展示怎么去创建一个绑定的服务,包括从其他应用组件中去绑定服务,然而,你应该涉及service文档去获得一些服务的信息,例如怎么去从一个服务去分发通知 ,把服务运行于前台等等。

The Basics


A bound service is an implementation of the Service class that allows other applications to bind to it and interact with it. To provide binding for a service, you must implement the onBind() callback method. Thismethod returns anIBinder object  that defines the programming interface that clients can use to interact with the service.

一个绑定的服务是一个service的实现,允许其他的应用绑定并且可以交互,你要实现onbind方法才是提供对服务的绑定,这个方法返回一个Ibind对象,这个对象是一个定义的接口,客户端能够用它来和服务进行交互

A client can bind to the service by calling bindService(). When it does, it must provide an implementation of ServiceConnection, which monitors the connection with the service. ThebindService() method returns immediately without a value, but when the Android system creates the connection between theclient and service, it callsonServiceConnected() on theServiceConnection, to deliver theIBinder that the client can use to communicate with the service.

一个客户端通过调用bindservice能够绑定一个服务,这样做必须提供一个serviceConnection 这个服务连接监控和服务的连接,这个bindservice方法会立刻不带值返回,但是当android系统在客户端和服务之间建立一个连接的话 它会调用 ServiceConnection 的onserviceConnect方法,去分配用户客户端和服务通信的Ibinder


Multiple clients can connect to the service at once. However, the system calls your service'sonBind() method to retrieve theIBinder only when the first client binds. The system then delivers the sameIBinder to any additional clients that bind, without callingonBind() again.

多个客户端能够连接服务,但是系统只会当第一个客户端绑定的时候调用onbind方法去取回Ibinder ,系统会分配相同的Ibinder给其他的客户端而不是去在此调用onbind方法。

When the last client unbinds from the service, the system destroys the service (unless theservice was also started bystartService()).


当最后一个客户从服务上解绑定的时候系统会销毁这个服务,(除非这个服务也被通过startservice启动)

When you implement your bound service, the most important part is defining the interface that youronBind() callback method returns. There are a few different ways you can define your service'sIBinder interface and the following section discusses each technique.


当你实现绑定的服务 ,最终要的一部分是定义你的onbind方法返回的接口,定义服务Ibinder接口有几个不同的方式,下面的章节会讨论每一个技巧


Creating a Bound Service


When creating a service that provides binding, you must provide an IBinderthat provides the programming interface that clients can use to interact with the service. Thereare three ways you can define the interface:


当你创建一个提供绑定的服务,你必须提供一个Ibinder程序接口用户客户端和服务进行交互,下面有三种方式你可以定义接口


Extending the Binder class
If your service is private to your own application and runs in the same process as the client(which is common), you should create your interface by extending the Binder class and returning an instance of it from onBind(). The client receives the Binder and can use it to directly access public methods available in either the Binderimplementation or even the Service.

This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not create your interface this way is because your service is used by other applications or across separate processes.

           如果你的服务队你的应用是私有的并且和客户端运行于同一个进程(这个是常见的),你应该通过集成binder类来创建你的接口,这会通过onbind返回一个实例,

客户端接收到这个binder 并且能够用它直接访问binder实现或者service中的公共方法,当你的服务仅仅运行于你自己的应用后台这是最好的选择技巧,你不用这个方式创建接口实例的唯一原因就是这个服务要被其他应用使用或者其他别的进程。


        

Using a Messenger
If you need your interface to work across different processes, you can create an interface for the service with a Messenger. In this manner, the service defines a Handler that responds to different types of Message objects. This Handleris the basis for a Messenger that can then share an IBinderwith the client, allowing the client to send commands to the service using Message objects. Additionally, the client can define a Messenger ofits own so the service can send messages back.

This is the simplest way to perform interprocess communication (IPC), because theMessenger queues all requests into a single thread so that you don't have to design your service to be thread-safe.

如果你的接口需要不同的进程间工作你可以用Messager为你的服务创建接口,用这种方式,服务能够定一个handler来响应不同类型的消息对象,这个handler是能够分享给客户端分享Ibinder 的messager的基础,它允许客户端通过消息对象发送指令给服务,另外 客户端可以定义一个自己的消息使者,一边服务能够发送消息回来。

          这个是处理进程间通信简单的方式,因为消息对立所有请求都在一个单一的线程,所以你不用设计你的服务线程安全


Using AIDL
AIDL (Android Interface Definition Language) performs all the work to decompose objects into primitives that the operating system can understand and marshall them across processes to perform IPC. The previous technique, using a Messenger, is actually based on AIDL as its underlying structure. As mentioned above, the Messenger creates a queue of all the client requests in a single thread, so the service receives requests one at a time. If,however, you want your service to handle multiple requests simultaneously, then you can use AIDLdirectly. In this case, your service must be capable of multi-threading and be built thread-safe.   
AIDL(android接口定义语言)去执行所有工作去分解成计算机能够理解和按次序的IPC执行的基元,上一个关于Messager的技巧就是基于AIDL的底层结构。就像上面提到的,Messager创建一个所有客户端请求的队列在一个线程中,所以服务接收这些请求一次一个,然而 如果你要求你的服务同时能够处理多个请求,那么你能够直接使用AIDL ,这样的话,你的服务必须能够多线程而且是基于线程安全的。

To use AIDL directly, you must create an .aidl file that defines the programming interface. The Android SDK tools use this file to generate an abstract class that implements the interface and handles IPC, which you can then extend within your service.

为了直接用AIDL,你必须创建一个.aidl文件,这个文件定义了程序接口,android的sdk工具用这个文件产生一个实现这个接口并且处理ipc的抽象类,这样你能够在你的服务里面继承了 

Note: Most applications should not use AIDL to create a bound service, because it may require multithreading capabilities and can result in a more complicated implementation. As such, AIDL is not suitable for most applicationsand this document does not discuss how to use it for your service. If you're certain that you need to use AIDL directly, see theAIDLdocument


注意:大部分的应用不会用aidl去绑定一个服务,因为,因为它要求多线程的并且会产生一个复杂的实现,因为,aidl不适合大部分的应用,这个文档一而不会讨论怎么在你的服务里面去使用,如果你一定要直接使用aidl ,参看aidl文档。


Extending the Binder class

If your service is used only by the local application and does not need to work across processes,then you can implement your ownBinder class that provides your client directaccess to public methods in the service.

如果你的服务仅仅使用在你的自己的应用上并不会需要进程间工作,那么你可以实现一个提供你客户端直接访问服务公共方法的Binder类

Note: This works only if the client and service are in the same application and process, which is most common. For example, this would work well for a music application that needs to bind an activity to its own service that's playing music in thebackground.


注意: 这个方式仅仅放你的客户端和服务在同一个应用和同一个进程上。这也是最常见的。例如,这对一个需要绑定到activity的运行在后台服务的音乐应用会工作的很好

Here's how to set it up:

  1. In your service, create an instance of Binder that either:
    • contains public methods that the client can call
    • returns the current Service instance, which has public methods theclient can call
    • or, returns an instance of another class hosted by the service with public methods theclient can call
  2. Return this instance of Binder from theonBind() callback method.
  3. In the client, receive the Binder from theonServiceConnected() callback method andmake calls to the bound service using the methods provided.
怎么去设置:

1 在你的服务里创建一个binder的实例:

    包含客户端能够调用的公共方法;

   返回包含客户端能够调用公共方法的服务的实例

   或者 返回一个包含客户端能够访问的公共方法的服务的宿主类的实例

2 ,onbind回调方法返回这个binder实例

3 在客户端 ,从onserviceconnecter回调方法中接受到binder并且用所提供的方法调用绑定的服务。


For example, here's a service that provides clients access to methods in the service throughaBinder implementation:


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);
    }
}
The LocalBinder provides the getService() method for clients to retrieve thecurrent instance of LocalService. This allows clients to call public methods in the service. For example, clients can call getRandomNumber() from the service.

LocalBinder 提供了一个getservice方法供哭护短去接收当前LocalService的实例,这个允许客户端调用服务的公共方法,例如,客户端能够调用服务的getRandomNumber方法

Here's an activity that binds to LocalService and calls getRandomNumber()when a button is clicked:


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

The above sample shows how the client binds to the service using an implementation ofServiceConnection and theonServiceConnected() callback. The nextsection provides more information about this process of binding to the service.

上面的例子展示了客户端怎么用serviceconnection和onserviceconnect方法绑定一个服务,西面章节会提供个多的关于绑定服务的信息


Note: The example above doesn't explicitly unbind from the service,but all clients should unbind at an appropriate time (such as when the activity pauses).

注意:上面的这个例子没有指出从服务上解绑定,但是所有de客户端都应该在合适的时间解绑定服务(例如当activity暂停的时候)


Using a Messenger

If you need your service to communicate with remote processes, then you can use a Messenger to provide the interface for your service. This technique allowsyou to perform interprocess communication (IPC) without the need to use AIDL.


如果你的服务需要去核远端进程通信,那么你可以使用Messager为你的服务提供接口 ,这个技巧允许你不适用aidl也能执行进程间通信;


Here's a summary of how to use a Messenger:

服务实现一个接收从客户端调用的回调的handler
这个handler用于创建一个messenger对象(指向handler的引用)
Messenger 创建一个从onbind返回到客户端的Ibinder
客户端是这个Ibinder实例化这个messenger(指向服务的handler),客户端用它向服务器发送消息对象
服务接受每一个消息在它的handler里,特别是handemessage方法里

In this way, there are no "methods" for the client to call on the service. Instead, the client delivers "messages" ( Message objects) that the service receives in its Handler

这种方式,没有客户端向服务器调用的方法,客户端提供消息(消息对象),服务在它的handler接收消息

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();
    }
}


Notice that the handleMessage() method in theHandler is where the service receives the incoming Messageand decides what to do, based on thewhat member.

注意handler里面的handlemessage方法是基于what成员变量来接收传过来的消息决定做什么

All that a client needs to do is create a Messenger based on theIBinder returned by the service and send a message usingsend(). For example, here's a simple activity that binds to theservice and delivers theMSG_SAY_HELLO message to the service:

客户端所要做的就是穿件一个基于被服务返回的Ibinder的Messenger,然后用send发送消息,例如下面的例子;


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

Notice that this example does not show how the service can respond to the client. If you want theservice to respond, then you need to also create a Messenger in the client. Thenwhen the client receives the onServiceConnected() callback, it sends a Message to the service that includes the client's Messenger in the replyTo parameterof the send() method.
注意这个例子没有展示服务怎么回应客户端,如果你想要服务回应客户端,那么你需要在客户端也要创建一个messenger 那么当客户端接受onservicerconnecter回调的时候

它会发送到服务一个包含在send函数的replyto 参数的客户端信息。

Binding to a Service


Application components (clients) can bind to a service by callingbindService(). The Android system then calls the service's onBind() method, which returns an IBinder for interacting with the service.

The binding is asynchronous. bindService() returns immediately and does not return the IBinder to the client. To receive the IBinder, the client must create an instance of ServiceConnection and pass it to bindService(). The ServiceConnection includes a callback method that thesystem calls to deliver the IBinder.

Note: Only activities, services, and content providers can bindto a service—you cannot bind to a service from a broadcast receiver.

应用组件(客户端)能够通过调用bindservice方法来绑定一个服务,android系统会调用一个服务的onbind方法,它会反悔一个用于和service交互的Ibinder。
服务的绑定是异步的:bindservice方法会立刻返回,但是并不会返回给客户端一个Ibinder,客户端必须创建一个serviceConnection实例来接受Ibinder 并且把这个实例传递给bindservice' serviceConection包含了一个系统调用传递的Bbinder的回调方法

注意:只有activity  service 和 contentProvider 能够绑定一个服务,不能使用广播接受者来绑定服务

So, to bind to a service from your client, you must:

  1. Implement ServiceConnection.

    Your implementation must override two callback methods:

    onServiceConnected()
    The system calls this to deliver the IBinder returned by the service's onBind() method.
    onServiceDisconnected()
    The Android system calls this when the connection to the service is unexpectedly lost, such as when the service has crashed or has been killed. This is not called when theclient unbinds.
  2. Call bindService(), passing the ServiceConnection implementation.
  3. When the system calls your onServiceConnected() callback method, you can begin making calls to the service, usingthe methods defined by the interface.
  4. To disconnect from the service, call unbindService().

    When your client is destroyed, it will unbind from the service, but you should always unbindwhen you're done interacting with the service or when your activity pauses so that the service canshutdown while its not being used. (Appropriate times to bind and unbind is discussedmore below.)

所以绑定一个服务,你必须:
1 实现一个serviceconnection   你的实现必须重载两个回调方法:
onserviceconnect
  系统调用这个方法传递从服务的onbind方法返回的Ibinder
onserviceDisconnected
  当连接异常丢失的时候系统调用这个方法,例如当服务坠毁 或者被杀掉,客户端的解绑定不会调用这个方法
2 调用bindservice 传入 serviceconnection实现
3 当服务调用onserviceconnect方法时,你也可以开始用在接口中定义的方法调用服务。
4 调用unbindservice能够从service上关闭连接
 当你的客户端被销毁,它会从服务上被解绑定,当你的交互完成的时候或者再activity暂停的时候你应该解绑定服务,这样能保证当服务不用的时候它是关闭的
(后面会讨论合适的时间去绑定和解绑定)


     For example, the following snippet connects the client to the service created above by extending the Binder class, so all it must do is cast the returned IBinder to the LocalService class and request the LocalService instance:

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established
    public void 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
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

With this ServiceConnection, the client can bind to a service by passingit to bindService(). For example:

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


bindService的第一个参数是一个指定要绑定服务的名称的Intent(认为这个intent可能是隐式的 )
第二个参数是serviceConnect的对象
第三个参数是一个指定绑定选项的标志,通用使用BIND_AUTO_create来创建这个服务如果这个服务不存在的话,其他可能的值有 BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND 或者0表示空


Additional notes

Here are some important notes about binding to a service:

  • You should always trap DeadObjectException exceptions, which are thrown when the connection has broken. This is the only exception thrown by remote methods.
  • Objects are reference counted across processes.
  • You should usually pair the binding and unbinding during matching bring-up and tear-down moments of the client's lifecycle. For example:
    • If you only need to interact with the service while your activity is visible, youshould bind during onStart() and unbind during onStop().
    • If you want your activity to receive responses even while it is stopped in thebackground, then you can bind during onCreate() and unbindduring onDestroy(). Beware that this implies that your activity needs to use the service the entire time it's running (even in the background), so if the service is in another process, then you increase the weight of the process and it becomes more likely that the system will kill it.

    Note: You should usually not bind and unbindd uring your activity's onResume() and onPause(), because these callbacks occur at every lifecycle transition and you should keep the processing that occurs at these transitions to a minimum. Also, if multiple activities in your application bind to the same service and there is a transition between two of those activities, the service may be destroyed and recreated as the current activity unbinds(during pause) before the next one binds (during resume). (This activity transition for how activities coordinate their lifecycles is described in the Activitiesdocument.)

这有一些关于绑定服务的重要的注意事项:

你应该捕捉到DeadObjectException,这个会在连接断开时抛出,这是远程方法抛出的唯一的异常
跨进程的对象引用数

通常情况你应该匹配客户端的生命周期带来和销毁的绑定和解绑定 例如;
如果再你的activity可见的情况下和服务进行交互,你应该在onstart中绑定 在onstop中销毁
如果你想要你的activity即使在后台停止也能接收到响应,你可以在oncreate中绑定 在ondestory中销毁,这就意味着activity需要用这个服务在它的整个运行期间(即使在后台运行),所以如果这个服务在其他的进程,那么你增加了进程的权重,系统杀死它就变得容易了
注意事项:你不应该在activity的onresume和onpause期间绑定和解绑定操作,因为这些回调发生在每一个生命周期的过渡阶段,你应该在这个过去阶段去保持处理这些的一个最低限度,如果多个activity在他们的生命周期的过渡阶段去绑定同一个服务,那么这个服务可能会被销毁掉 或者重建当activity解绑定(在暂停的时候)在下一个绑定之前(在开始的时候)(activity 的过渡协调的描述在activity 章节)

Managing the Lifecycle of a Bound Service


When a service is unbound from all clients, the Android system destroys it (unless it was also started with onStartCommand()). As such, you don't have to manage the lifecycle of your service if it's purely a boundservice—the Android system manages it for you based on whether it is bound to any clients.

However, if you choose to implement the onStartCommand() callback method, then you must explicitly stop the service, because the service is now considered to be started. In this case, the service runs until the service stops itself with stopSelf() or another component calls stopService(), regardless of whether it is bound to any clients.

Additionally, if your service is started and accepts binding, then when the system callsyour onUnbind() method, you can optionally returntrue if you would like to receive a call to onRebind() the next time a client binds to the service (instead of receiving a call to onBind()). onRebind() returns void, but the client still receives the IBinder in itsonServiceConnected() callback.Below, figure 1 illustrates the logic for this kind of lifecycle.


当一个服务被所有的客户端解绑定 ,android 系统会销毁它 (除非它也被onstartcommand启动),因此你不必去管理你这个服务的生命周期,如果这是一个纯粹的绑定服务的话,android系统会根据是否还有其他客户端去绑定来管理服务的生命周期
然而 如果选择了去实现onstartcommand回调方法,你必须去明确的关闭这个服务,因为这个服务是被明确启动的,因此无论服务是否绑定到其他客户端,这个服务会一直运行,直到它自己调用了stopself或者其它组件调用了stopservice
除此之外,如果你的服务是被启动的并且接受绑定,那么当系统调用解绑定的方法时,你可获得一个true当下一次客户端想要绑定服务的时候你接受一调用onreind(而不是调用inbind方法)
onrebind返回一个void 但是客户端仍够能从onserviceconnecte回调中接受到一个Ibinder 下图显示这种生命周期
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值