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

  • 相关阅读:
    4-MSP430定时器_定时器中断
    关于STM32的外部引脚中断的问题
    关于stm32的正交解码
    红外接收控制灯亮灭
    mack pro常用快捷键
    liunx操作系统安装<一>
    支付宝架构师:从工程师到架构师的成长之路
    maven之setting.xml的配置详解
    分布式之《保证分布式系统数据一致性的6种解决方案》
    Eclipse中jsp、js文件编辑时,卡死现象解决汇总
  • 原文地址:https://www.cnblogs.com/vus520/p/2561970.html
Copyright © 2011-2022 走看看