0
回答
理解Android系统的进程间通信原理------RPC机制
终于搞明白,存储TCO原来是这样算的>>>   

理解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 { 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方法在绑定到一个服务时才能实现返回该接口实例,进而对该实例进行相关操作。

 


原文链接:http://www.cnblogs.com/vus520/archive/2012/03/10/2561970.html
<无标签>
举报
长平狐
发帖于5年前 0回/287阅
顶部