zoukankan      html  css  js  c++  java
  • 理解Android系统的进程间通信原理RPC机制

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

  • 相关阅读:
    形象理解ERP(转)
    禁用windows server 2008 域密码复杂性要求策略
    How to adding find,filter,remove filter on display method Form
    Windows Server 2008 R2激活工具
    How to using bat command running VS development SSRS report
    Creating Your First Mac AppGetting Started
    Creating Your First Mac AppAdding a Track Object 添加一个 Track 对象
    Creating Your First Mac AppImplementing Action Methods 实现动作方法
    Creating Your First Mac AppReviewing the Code 审查代码
    Creating Your First Mac AppConfiguring the window 设置窗口
  • 原文地址:https://www.cnblogs.com/vus520/p/2561970.html
Copyright © 2011-2022 走看看