展会信息港展会大全

理解Android系统的进程间通信原理之RPC机制
来源:互联网   发布日期:2016-01-13 21:52:55   浏览:4281次  

导读:理解Android系统中的轻量级解决方案RPC的原理,需要先回顾一下JAVA中的RMI(Remote Method Invocation)这个易于使用的纯JAVA方案(用来实现分布式应用)。有关RMI的相关知识,可以通过下图来归纳:Android中的......

理解Android系统中的轻量级解决方案RPC的原理,需要先回顾一下JAVA中的RMI(Remote Method Invocation)这个易于使用的纯JAVA方案(用来实现分布式应用)。有关RMI的相关知识,可以通过下图来归纳:

Android中的RPC也是参考了JAVA中的RMI方案,这里我们再详细了解一下RPC的实现过程。

Android中的RPC机制是为 了实现一个进程使用另一个进程中的远程对象,它使用了Android自己的AIDL(接口定义语言),使用户很方便地定义出一个接口作为规范,通过一个远 程Service为代理 ,客户端在绑定该远程Service过程中获取远程对象,进而使用该对象。可参考下图所示:

补充:RPC的另一个目的是对客户端只声明接口及方法,隐藏掉具体实现类,供客户端直接获取此接口实例。

实例代码:

实例一:通过Service来远程调用一个接口子类的函数方法

功 能描述:在MainActivity中通过绑定MyService服务类,来远程调用MyPlayer(实现了IPlayer接口)的方法过程。需要定义 一个IPlayer.aidl文件,ADT工具会自动生成一个IPlayer接口类,然后再由MyPlayer继承IPlayer接口类中的静态内部抽象 类,实现接口方法,进而供其它应用程序远程调用。(在本例中为了方便,MainActivity与MyService类同处一个应用程序中,实现运用时, 可以不在同一个应用程序中,只要有权限访问MyService服务,就能得到IPlayer接口,进而执行该接口实例方法)

程序清单:IPlayer.aidl

package com.magc.rpc;

interface IPlayer

{

void setName(String name);

void addFile(String f_name);

String ToString();

}

程序清单:IPlayer.java (ADT根据上面IPlayer.aidl文件自动生成,不能编辑该文件)

/*

* This file is auto-generated.DO NOT MODIFY.

* Original file: F:\\work\\Android_App\\MyRPCService\\src\\com\\magc\\rpc\\IPlayer.aidl

*/

package com.magc.rpc;

public interface IPlayer extends android.os.IInterface

{

/** Local-side IPC implementation stub class. */

public static abstract class Stub extends android.os.Binder implements com.magc.rpc.IPlayer

{

private static final java.lang.String DESCRIPTOR = "com.magc.rpc.IPlayer";

/** Construct the stub at attach it to the interface. */

public Stub()

{

this.attachInterface(this, DESCRIPTOR);

}

/**

* Cast an IBinder object into an com.magc.rpc.IPlayer interface,

* generating a proxy if needed.

*/

public static com.magc.rpc.IPlayer asInterface(android.os.IBinder obj)

{

if ((obj==null)) {

return null;

}

android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);

if (((iin!=null)&&(iin instanceof com.magc.rpc.IPlayer))) {

return ((com.magc.rpc.IPlayer)iin);

}

return new com.magc.rpc.IPlayer.Stub.Proxy(obj);

}

public android.os.IBinder asBinder()

{

return this;

}

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException

{

switch (code)

{

case INTERFACE_TRANSACTION:

{

reply.writeString(DESCRIPTOR);

return true;

}

case TRANSACTION_setName:

{

data.enforceInterface(DESCRIPTOR);

java.lang.String _arg0;

_arg0 = data.readString();

this.setName(_arg0);

reply.writeNoException();

return true;

}

case TRANSACTION_addFile:

{

data.enforceInterface(DESCRIPTOR);

java.lang.String _arg0;

_arg0 = data.readString();

this.addFile(_arg0);

reply.writeNoException();

return true;

}

case TRANSACTION_ToString:

{

data.enforceInterface(DESCRIPTOR);

java.lang.String _result = this.ToString();

reply.writeNoException();

reply.writeString(_result);

return true;

}

}

return super.onTransact(code, data, reply, flags);

}

private static class Proxy implements com.magc.rpc.IPlayer

{

private android.os.IBinder mRemote;

Proxy(android.os.IBinder remote)

{

mRemote = remote;

}

public android.os.IBinder asBinder()

{

return mRemote;

}

public java.lang.String getInterfaceDescriptor()

{

return DESCRIPTOR;

}

public void setName(java.lang.String name) throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

android.os.Parcel _reply = android.os.Parcel.obtain();

try {

_data.writeInterfaceToken(DESCRIPTOR);

_data.writeString(name);

mRemote.transact(Stub.TRANSACTION_setName, _data, _reply, 0);

_reply.readException();

}

finally {

_reply.recycle();

_data.recycle();

}

}

public void addFile(java.lang.String f_name) throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

android.os.Parcel _reply = android.os.Parcel.obtain();

try {

_data.writeInterfaceToken(DESCRIPTOR);

_data.writeString(f_name);

mRemote.transact(Stub.TRANSACTION_addFile, _data, _reply, 0);

_reply.readException();

}

finally {

_reply.recycle();

_data.recycle();

}

}

public java.lang.String ToString() throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

android.os.Parcel _reply = android.os.Parcel.obtain();

java.lang.String _result;

try {

_data.writeInterfaceToken(DESCRIPTOR);

mRemote.transact(Stub.TRANSACTION_ToString, _data, _reply, 0);

_reply.readException();

_result = _reply.readString();

}

finally {

_reply.recycle();

_data.recycle();

}

return _result;

}

}

static final int TRANSACTION_setName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

static final int TRANSACTION_addFile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

static final int TRANSACTION_ToString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);

}

public void setName(java.lang.String name) throws android.os.RemoteException;

public void addFile(java.lang.String f_name) throws android.os.RemoteException;

public java.lang.String ToString() throws android.os.RemoteException;

}

程序清单:MyPlayer.java(实现IPlayer的静态内部抽象类Stub)

package com.magc.rpc;

import android.os.RemoteException;

import android.util.Log;

import com.magc.rpc.IPlayer.Stub;

/**

*

* @author magc

* 实现IPlayer接口类中的静态内部抽象类,即实现IPlayer接口方法

* 将来供其它应用程序远程调用执行方法

*/

public class MyPlayer extends Stub {

private String name="";

@Override

public void addFile(String fName) throws RemoteException {

System.out.println("add file ...");

}

@Override

public void setName(String name) throws RemoteException {

this.name = name;

Log.i("magc", "setName--"+name);

}

public String ToString()

{

String str = "MyPlayer--"+name;

Log.i("magc", "MyPlayer--"+name);

return str;

}

}

程序清单:MyService.java (一个Service类,供其它程序来远程绑定,返回IPlayer接口)

package com.magc.rpc;

import com.magc.rpc.IPlayer.Stub;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

/**

*

* @author magc

* 此服务类作为一个代理角色,供其它应用程序绑定,并返回接口实例

*

* 可看作是代理模式的应用

*/

public class MyService extends Service {

private Stub player = new MyPlayer();

@Override

public IBinder onBind(Intent arg0) {

return player;

}

@Override

public void onCreate() {

super.onCreate();

}

}

程序清单:MainActivity.java (作为客户端远程调用IPlayer接口方法)

package com.magc.rpc;

import android.app.Activity;

import android.content.ComponentName;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

/**

*

* @author magc

* 作为一个客户端通过绑定MyService服务,实现远程调用IPlayer接口方法

*

*/

public class MainActivity extends Activity {

privateString ACTION="com.magc.rpc.action.MYSERVICE";

private IPlayer player;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Intent intent = new Intent();

intent.setAction(ACTION);

//绑定MyService服务

bindService(intent, conn, BIND_AUTO_CREATE);

}

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceDisconnected(ComponentName name) {

}

/**

* 绑定MyService服务后,返回IPlayer接口,进而调用该接口方法

*/

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

Log.i("magc", "bind service .....");

player = IPlayer.Stub.asInterface(service);

if(player!=null)

{

try {

player.setName("magc");

player.ToString();

} catch (RemoteException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

};

}

程序清单:AndroidManifest.xml (注册Activity和Service)

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.magc.rpc"

android:versionCode="1"

android:versionName="1.0">

<uses-sdk android:minSdkVersion="9" />

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".MainActivity"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<service android:name=".MyService">

<intent-filter>

<action android:name="com.magc.rpc.action.MYSERVICE" />

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</service>

</application>

</manifest>

上面Android应用程序运行后结果如下所示:

小结:

1、重点理解Android中对AIDL文件的定义,以及理解ADT工具自动生成的接口类IPlayer,特别是它的静态内部类Stub以及Stub的asInterface方法,

2、Service作为一个代理角色,在其它应用程序通过Stub类的asInterface方法在绑定到一个服务时才能实现返回该接口实例,进而对该实例进行相关操作。

赞助本站

人工智能实验室

相关热词: RPC机制

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港