Android开发文档翻译之——Bound Services

来源:互联网 发布:广数928螺纹编程格式 编辑:程序博客网 时间:2024/05/19 01:06

绑定状态下的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的生命周期如上图所示,在此不再赘述。

1 0
原创粉丝点击