Android Service系列(二十)创建bound Service

Creating a bound service

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

有三种定义结构的方法

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 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.

翻译:应用内

 

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 Handler is the basis for a Messenger that can then share an IBinder with the client, allowing the client to send commands to the service using Message objects. Additionally, the client can define a Messenger of its own, so the service can send messages back.

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

翻译:使用Messager

 

Using AIDL

Android Interface Definition Language (AIDL) decomposes objects into primitives that the operating system can understand and marshals 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 AIDL directly. In this case, your service must be thread-safe and capable of multi-threading.

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 ,Messager底层还是用的AIDL

Note: Most applications shouldn't 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 applications and this document does not discuss how to use it for your service. If you're certain that you need to use AIDL directly, see the AIDL document.

注意:一般不用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 own Binder class that provides your client direct access to public methods in the service.

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 the background.

注意:只是在应用内

Here's how to set it up:

  1.   In your service, create an instance of Binder that does one of the following:

  • Contains public methods that the client can call.
  • 翻译:包含公共方法
  • Returns the current Service instance, which has public methods the client can call.
  • 翻译:返回Service对象
  • Returns an instance of another class hosted by the service with public methods the client can call.
  • 翻译:返回service持有的对象

 

  2.  Return this instance of Binder from the onBind() callback method.

翻译:在onBind方法返回 Binder对象

  3.In the client, receive the Binder from the onServiceConnected() callback method and make calls to the bound service using the methods provided.

翻译:在客户端,在onServiceConnected方法接收Binder,调用service的方法

 

Note: The service and client must be in the same application so that the client can cast the returned object and properly call its APIs. The service and client must also be in the same process, because this technique does not perform any marshaling across processes.

注意:1.要在同一个应用,这样可以强转类型。 2 要在同一个进程,因为这个技术没有提供跨进程封装处理

 

For example, here's a service that provides clients with access to methods in the service through a Binderimplementation:

举例:

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder binder = 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 binder;
    }

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

The LocalBinder provides the getService() method for clients to retrieve the current 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的实例。

 

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, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        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 connection = 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 of ServiceConnection and the onServiceConnected() callback. The next section provides more information about this process of binding to the service.

翻译:下面提供binding to the service的更多信息

 

Note: In the example above, the onStop() method unbinds the client from the service. Clients should unbind from services at appropriate times, as discussed in Additional notes.

注意:要适时解绑

 

For more sample code, see the LocalService.java class and the LocalServiceActivities.java class in ApiDemos.

参考:ApiDemos.

 

Using a Messenger

使用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 allows you to perform interprocess communication (IPC) without the need to use AIDL.

翻译:使用Messager不用AIDL也能跨进程

Using a Messenger for your interface is simpler than using AIDL because Messenger queues all calls to the service. A pure AIDL interface sends simultaneous requests to the service, which must then handle multi-threading.

翻译:使用AIDL 更简单,Messenger 把all calls 放入队列。一个纯的AIDL 会同时发送多个请求给sercie,这样需要处理多线程问题。

 

For most applications, the service doesn't need to perform multi-threading, so using a Messenger allows the service to handle one call at a time. If it's important that your service be multi-threaded, use AIDL to define your interface.

翻译:不用多线程的话,就用Messenger就行

 

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

  1. The service implements a Handler that receives a callback for each call from a client.
  2. The service uses the Handler to create a Messenger object (which is a reference to the Handler).
  3. The Messenger creates an IBinder that the service returns to clients from onBind().
  4. Clients use the IBinder to instantiate the Messenger (that references the service's Handler), which the client uses to send Message objects to the service.
  5. The service receives each Message in its Handler—specifically, in the handleMessage() method.

翻译:下面总结如何用Messager

1.service实现一个handler

2.service 用handler来创建一个Messenger对象

3.Messenger 创建一个IBinder对象在onBind方法返回

4.客户端使用IBinder来初始化Messenger.

5.service在handler的handlerMessager里接收Message

 

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

Here's a simple example service that uses a Messenger interface:

翻译:这样的话,客户端没有方法可以调用,但是客户端可以deliver messager

下面举例

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.
     */
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    Messenger mMessenger;

    /**
     * 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();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
}

Notice that the handleMessage() method in the Handler is where the service receives the incoming Message and decides what to do, based on the what member.

翻译:handlerMessage 方法是接收Message以及决定如何处理的地方

 

All that a client needs to do is create a Messenger based on the IBinder returned by the service and send a message using send(). For example, here's a simple activity that binds to the service and delivers the MSG_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 bound;

    /**
     * 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);
            bound = 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;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) 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 (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
}

Notice that this example does not show how the service can respond to the client. If you want the service to respond, you need to also create a Messenger in the client. When the client receives the onServiceConnected() callback, it sends a Message to the service that includes the client's Messenger in the replyTo parameter of the send() method.

You can see an example of how to provide two-way messaging in the MessengerService.java (service) and MessengerServiceActivities.java (client) samples.

翻译:双向通信  replyto in message

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值