当前位置:操作系统 > 安卓/Android >>

Android ApiDemos示例解析(42):App->Service->Remote Service Binding

本例和下个例子Remote Service Controller 涉及到的文件有RemoteService.java ,IRemoteService.aidl, IRemoteServiceCallback.aidl 及ISecondary.aidl。

Android Interface Definition Language(AIDL)和其它一些支持远程方法调用RMI的系统的IDL类似,它定义了Service和Client 之间的使用接口约定,这种远程调用一般需要通过进程间通信机制(IPC)来实现。在Android系统,一个进程(Process)通常不能直接访问其它进程的内存空间,Android系统支持使用AIDL来实现使用不同进程间调用服务接口。

在设计AIDL接口之前,要意识到使用AIDL接口是通过直接函数调用的方法来进行的,但这种远程调用所发生的线程Thread随调用者是否和Service提供者属于同一进程Process的不同而不同:

如果调用者与Service属于同一个进程(可以称为Local Process),那么AIDL Call将使用与调用者同一线程执行。因此如果你的应用只使用Local Process来访问AIDL Call,那么根本就无必要使用AIDL接口,使用Binder即可,参见Android ApiDemo示例解析(39):App->Service->Local Service Binding。
如果使用Remote Process方式来调用AIDL ,Android将会使用由本进程管理的线程池(Thread pool)来分发函数调用。因此你的Service需要能够处理多进程触发的AIDL Call,换句话来说,AIDL接口的实现必须是Thread-safe的。
关键字oneway 可以修改远程调用的的行为,当使用oneway关键字时,remote call调用后立即返回,有点类似异步调用。
定义AIDL 接口的步骤如下:

AIDL接口定义使用Java Interface语法定义在 .aidl文件中,然后必须同时放在Service和Client 的 src目录下。 当使用Eclipse 编译时,Android SDK工具会根据 .aidl的接口定义自动生成对应的IBinder接口定义 (定义在gen目录下) Service必须实现由这个IBinder接口定义。 Client然后可以通过绑定Service来访问这些方法。

1. 创建. aidl 文件

AIDL接口定义使用和Java Interface定义同样的语法,每个.aidl文件只能定义一个调用接口,而且只能定义接口方法,不能含有静态变量定义。AIDL缺省支持 int ,long, char, boolean, String, CharSequence, List ,Map 变量类型,也可以引用其它 .aidl中定义的类型。

下面是IRemoteService.aidl 的定义,

[java] 
package com.example.android.apis.app; 
import com.example.android.apis.app.IRemoteServiceCallback; 
/**
 * Example of defining an interface for calling on to a remote service
 * (running in another process).
 */ 
interface IRemoteService { 
 /**
 * Often you want to allow a service to call back to its clients.
 * This shows how to do so, by registering a callback interface with
 * the service.
 */ 
 void registerCallback(IRemoteServiceCallback cb); 
 /**
 * Remove a previously registered callback interface.
 */ 
 void unregisterCallback(IRemoteServiceCallback cb);<br /> 

package com.example.android.apis.app;
import com.example.android.apis.app.IRemoteServiceCallback;
/**
 * Example of defining an interface for calling on to a remote service
 * (running in another process).
 */
interface IRemoteService {
 /**
 * Often you want to allow a service to call back to its clients.
 * This shows how to do so, by registering a callback interface with
 * the service.
 */
 void registerCallback(IRemoteServiceCallback cb);
 /**
 * Remove a previously registered callback interface.
 */
 void unregisterCallback(IRemoteServiceCallback cb);<br />
}
编译时,Android SDK 工具自动在gen目录下生成对应的 IRemoteService.java。

2. 实现这个AIDL接口

编译时,Android SDK 工具自动在gen目录下生成对应的 IRemoteService.java,这个文件中会定义一个子类Stub (IRemoteService.Stub),Stub定义了由.aidl 定义的抽象方法实现。除此之外,Stub还定义了几个Help 方法,比如asInterface() 参数为IBinder对象(通常由Client中的onServiceConnected()传入),返回一个Stub实例供Client使用。

下面是IRemoteService.Stub 在 RemoteService中的实现

[java]
/**
 * The IRemoteInterface is defined through IDL
 */ 
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { 
 public void registerCallback(IRemoteServiceCallback cb) { 
 if (cb != null) mCallbacks.register(cb); 
 } 
 public void unregisterCallback(IRemoteServiceCallback cb) { 
 if (cb != null) mCallbacks.unregister(cb); 
 } 
}; 
/**
 * The IRemoteInterface is defined through IDL
 */
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
 public void registerCallback(IRemoteServiceCallback cb) {
 if (cb != null) mCallbacks.register(cb);
 }
 public void unregisterCallback(IRemoteServiceCallback cb) {
 if (cb != null) mCallbacks.unregister(cb);
 }
};
3. Expose the interface to Clients

在定义.aidl 和实现AIDL接口定义后,就需要将这个接口提供给Client使用。方法是派生Service并提供onBind方法返回上面实现的Stub的一个实例。

[java]
public class RemoteService extends Service { 
... 
@Override 
public IBinder onBind(Intent intent) { 
 // Select the interface to return.  If your service only implements  
 // a single interface, you can just return it here without checking  
 // the Intent.  
 if (IRemoteService.class.getName().equals(intent.getAction())) { 
 return mBinder; 
 } 
 if (ISecondary.class.getName().equals(intent.getAction())) { 
 return mSecondaryBinder; 
 } 
 return null; 

public class RemoteService extends Service {
...
@Override
public IBinder onBind(Intent intent) {
 // Select the interface to return.  If your service only implements
 // a single interface, you can just return it here without checking
 // the Intent.
 if (IRemoteService.class.getName().equals(intent.getAction())) {
 return mBinder;
 }
 if (ISecondary.class.getName().equals(intent.getAction())) {
 return mSecondaryBinder;
 }
 return null;
}
RemoteService 中定义了两个.aidl 接口可供Client使用IRemoteService.aidl和ISecondary.aidl。

有了AIDL定义并在Service中定义了可供Client使用的AIDL实现。下面再来看看Client的实现步骤:

将. aidl定义包含着 src目录下,由于本例Service ,Client 都包含在ApiDemos中,.aidl已在src中定义了。
根据.aidl接口生成IBinder接口定义(编译时由Android SDK工具自动生成)。
实现ServiceConnection接口
调用Context.bindService 来绑定需调用的Service。
在ServiceConnection 的onServiceConnected方法中,根据传入的IBinder对象(被调用的Service),使用 YourInterfaceName.Stub.asInterface((IBinder)service)) 将 service转换为YourInterfaceName类型。
调用YourInterfaceName定义的方法,这里需要捕获DeadObjectException 异常,DeadObjectException会在链接断裂时抛出。
使用完Service,使用Context.unbindService断开与Service之间的绑定。
Remote Service Binding 例子中 Service 端实现了两个Service:

IRemoteService :提供registerCallback,unregisterCallback用来在RemoteCallbackList 中注册或注销一个Client的Callback。
ISecondary: 实际Client会调用的服务,getPid返回当前进程Process ID。basicTypes 介绍了一般参数类型用法,本例中Client为使用。
在RemoteService 的主线程中定义了一个mHandler,它每隔1秒钟将value值加1,并通过IRemoteServiceCallback 将这个新值发给注册过的Client。

[java] 
int value = ++mValue; 
// Broadcast to all clients the new value.  
final int N = mCallbacks.beginBroadcast(); 
for (int i=0; i<N; i++) { 
 try { 
 mCallbacks.getBroadcastItem(i).valueChanged(value); 补充:移动开发 , Android ,

CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,