一.Binder机制关系图:
二.远程服务
1.远程服务介绍
2.远程服务使用场景介绍
3.这里就先简单介绍下Messenger的方式:
通信步骤
private class ServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if(msg.what == RECEIVE_MESSAGE){
Bundle data = msg.getData();
if(data != null){
String str = data.getString("msg");
Log.i("DemoLog", "收到客户端如下信息: " + str);
}
//通过Message的replyTo获取到客户端自身的Messenger,
//Service可以通过它向客户端发送消息
clientMessenger = msg.replyTo;
if(clientMessenger != null){
Log.i("DemoLog", “服务端向客户端回信");
Message msgToClient = Message.obtain();
msgToClient.what = SEND_MESSAGE;
//可以通过Bundle发送跨进程的信息
Bundle bundle = new Bundle();
bundle.putString("msg", "你好,客户端,我是服务端”);
msgToClient.setData(bundle);
try{
clientMessenger.send(msgToClient);
}catch (RemoteException e){
e.printStackTrace();
Log.e("DemoLog", "thisservice向客户端发送信息失败: " + e.getMessage());
}
}
}
}
}
Messenger serviceMessenger =new Messenger(newServiceHandler())
publicIBinder onBind(Intent intent) {
//获取Service自身Messenger所对应的IBinder,并将其发送共享给所有客户端
returnserviceMessenger.getBinder();
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
serviceMessenger = new Messenger(binder);
Message msg = Message.obtain();
msg.what = SEND_MESSAGE;
Bundle data = new Bundle();
data.putString("msg", "你好,我是客户端");
msg.setData(data);
//需要将Message的replyTo设置为客户端的clientMessenger,
//以便Service可以通过它向客户端发送消息
msg.replyTo = clientMessenger;
try {
serviceMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
Log.i("DemoLog", "客户端向service发送消息失败: " + e.getMessage());
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//客户端与Service失去连接
serviceMessenger = null; }
};
其他注意点:
private Intent getExplicitIapIntent() {
PackageManager pm = mContext.getPackageManager();
Intent implicitIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
List<ResolveInfo> resolveInfos = pm.queryIntentServices(implicitIntent, 0);
// Is somebody else trying to intercept our IAP call?
if (resolveInfos == null || resolveInfos.size() != 1) {
return null;
}
ResolveInfo serviceInfo = resolveInfos.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
Intent iapIntent = new Intent();
iapIntent.setComponent(component);
return iapIntent;
}
4.AIDL(Android Interface Definition Language)
(1).使用AIDL设计远程接口(Designing a Remote Interface Using AIDL)
由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。
通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作。
AIDL (Android Interface Definition Language)是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
(2).使用AIDL实现IPC(Implementing IPC Using AIDL)
使用AIDL实现IPC服务的步骤是:
创建.aidl文件(Create an .aidl File)
public class RemoteService extends Service {
...
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* The IRemoteInterface is defined through IDL
*/
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public void registerCallback(IRemoteServiceCallback cb) {
//注册操作
}
};
}
使用可打包接口传递参数Pass by value Parameters using Parcelables
1. 使该类实现Parcelabel接口。
2. 实现public void writeToParcel(Parcel out) 方法,以便可以将对象的当前状态写入包装对象中。
3. 增加名为CREATOR的构造器到类中,并实现Parcelable.Creator接口。
客户端访问服务,调用对应接口,实现操作
2. 实现ServiceConnection
3. 调用Context.bindService(),传递ServiceConnection的实现
4. 在ServiceConnection.onServiceConnected()方法中会接收到IBinder对象,调用YourInterfaceName.Stub.asInterface((IBinder)service)将返回值转换为YourInterface类型
5. 调用接口中定义的方法。应该总是捕获连接被打断时抛出的DeadObjectException异常,这是远端方法唯一的异常。
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
IRemoteService mService = IRemoteService.Stub.asInterface(service);
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
// so there is no need to do anything here.
}
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
}}