当前位置: 代码迷 >> Android >> 解Android系统的进程间通信原理(2)-RPC机制(转)
  详细解决方案

解Android系统的进程间通信原理(2)-RPC机制(转)

热度:73   发布时间:2016-05-01 13:43:58.0
解Android系统的进程间通信原理(二)----RPC机制(转)

解Android系统的进程间通信原理(二)----RPC机制

理解Android系统中的轻量级解决方案RPC的原理,需要先回顾一下JAVA中的RMI(Remote Method Invocation)这个易于使用的纯JAVA方案(用来实现分布式应用)。有关RMI的相关知识,可以通过下图来归纳:
RMI原理 (2)
Android中的RPC也是参考了JAVA中的RMI方案,这里我们再详细了解一下RPC的实现过程。
Android中的RPC机制是为了实现一个进程使用另一个进程中的远程对象,它使用了Android自己的AIDL(接口定义语言),使用户很方便地定义出一个接口作为规范,通过一个远程Service为代理 ,客户端在绑定该远程Service过程中获取远程对象,进而使用该对象。可参考下图所示:
Android的RPC原理及应用 (2)
补充: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 {    private  String 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方法在绑定到一个服务时才能实现返回该接口实例,进而对该实例进行相关操作。
待续
  相关解决方案