绑定状态下的service
Bound Service是一种c/s接口中的server端。其允许其他组件绑定到service,发送请求,接收响应,甚至进行进程间的交互(IPC)Bound Service通常只在有其他组件需要服务时运行,并不单独运行在后台。
本文档主要内容是如何创建一个bound service,包括在其他应用中绑定该service。如果你对service的基础概念不是太熟悉,建议你先看看我的另外一篇博客Android开发文档翻译之-Services

基础概念
Bound Service是service的一种实现方式。通过该方式其他应用程序可以绑定到该service并与其交互。你需要覆写onBind()函数来提供该功能。这个方法返回一个IBinder对象用来提供与service交互的接口。
client端程序通过调用bindService()来绑定service。调用该方法需要提供一个ServiceConnection对象,来监视与service的连接状态。bindService()会立即返回,并且在系统创建连接后回调onServiceConnected()函数,并且返回IBinder对象来供client端交互。

多个client端可以在同一时间绑定同一个service。然而用户只会接到一个onBind()回调。除了第一个绑定到service的对象会通过onBind()得到一个IBinder对象,其他时候系统都会直接将这个IBinder对象返回,并且不再调用onBind()函数。当最后一个client解绑时,系统会销毁这个service。

当你实现你的bound service时,最重要的一步是定义IBinder接口。以下是几种定义IBinder接口的方式:

1.继承Binder类
通常而言,如果你的service仅提供给你自己的应用程序使用,你应该提供你的接口通过继承Binder类,并且在onBInd()中返回。client端接收这个Binder对象,并且可以直接访问它的共有方法以及service中的共有方法。

2.使用Messenger
如果你需要一个在不同进程间工作的接口,你可以通过Messenger来创建service。这种方式下,service定义一个Handler来响应不同类型的Message。Handler类是用来提供一个IBinder对象的基础。通过Messenger,client端可以发送消息到server端。同样的,client端可以定义一个Messenger来接收service的消息回调。
注:这是IPC机制的一种简单方式。由于Messenger将所有的请求放入一个单线程的消息队列中,因此你设计的service是线程安全的。

3.使用AIDL
AIDL(Android Interface Define Language)是一种描述进程间通信的一种语言。刚刚介绍的Messenger就是一种基于AIDL的技术。如果你希望你的service能够处理多个并发的请求,那么你可以直接使用AIDL。这种情况下,你的service必须有多线程的执行能力并且需要是线程安全的。

PS:大部分程序是不需要AIDL的。因为AIDL需要拥有多线程处理能力,并且会使得情况更加复杂。因此,AIDL对于绝大部分应用是不适用的。本文也不打算介绍该技术,如果你确定你要使用该技术,请查看我的另外一篇博文:Android开发文档翻译之——AIDL

继承Binder类
你可以按以下步骤来实现:
1.在service中,创建一个Binder的实例,该Binder类需要满足:1)包含公有方法供client端调用;2)返回当前service的实例,该实例中包含公有方法给client端调用;3)如果不满足2),则返回一个service的内部类的实例,该内部类中提供了公有方法供client端调用。
2.在onBind()方法中返回Binder的实例。
3.在client端,通过onServiceConnected()函数接收Binder对象并且调用相关接口方法。

ps:service和client需要在同一应用的一个理由是你需要强制转换返回的IBinder对象。service和client必须要在相同的进程,因为该技术没有提供任何跨进程间通信的方式。

以下是一个继承IBinder类的示例:

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的实例。因此client端可以调用service的公有方法。例如,getRandomNumber()。

以下是一个activity绑定service并调用其公有方法的相关代码:

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

使用Messenger
如果你的service需要和远端进程进行通信,那么你需要使用Messenger为你的service提供一个接口。这个技术允许你在不通过AIDL技术的前提下完成IPC。
以下是使用Messenger的步骤:
1.service实现Handler类来接收client端的回调。
2.通过该Handler类产生Messenger的实例。
3.Messenger产生一个IBinder类的实例并在onBinder()中返回。
4.client端使用IBinder对象来实例一个Messenger对象(该对象持有Handler的引用),通过该对象来向service端发送消息。
5.service在handlerMessage()中执行相关操作。

以下是一个使用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();
    }
}

client端的代码如下:

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

上面两段代码较为简单,就不做过多的解释了。

Messenger和AIDL的比较
当你需要进程间通信时,使用Messenger是比AIDL更为简单的一种方式,因为Messenger依次的将请求放进请求队列中,而AIDL同时的将所有请求发送至service,因此你需要处理多线程的问题。
大部分应用程序不需要处理多线程情况,因此Messenger是更好的选择。如果你确实要在多线程情况下处理问题,那么使用AIDL来实现吧。

管理Bound Service的生命周期


Bound Service的生命周期如上图所示,在此不再赘述。