TShopping

 找回密碼
 註冊
搜索
查看: 409|回復: 0

[教學] 理解Android系統的進程間通信原理(二)----RPC機制

[複製鏈接]
發表於 2014-11-25 00:01:49 | 顯示全部樓層 |閱讀模式
 
Push to Facebook Push to Plurk Push to Twitter 
理解Android系統中的輕量級解決方案RPC的原理,需要先回顧一下JAVA中的RMI(Remote Method Invocation)這個易於使用的純JAVA方案(用來實現分佈式應用)。有關RMI的相關知識,可以通過下圖來歸納:
1.png
Android中的RPC也是參考了JAVA中的RMI方案,這裡我們再詳細了解一下RPC的實現過程。
Android中的RPC機制是為了實現一個進程使用另一個進程中的遠程對象,它使用了Android自己的AIDL(接口定義語言),使用戶很方便地定義出一個接口作為規範,通過一個遠程Service為代理,客戶端在綁定該遠程Service過程中獲取遠程對象,進而使用該對象。可參考下圖所示:
2.png
補充:RPC的另一個目的是對客戶端只聲明接口及方法,隱藏掉具體實現類,供客戶端直接獲取此接口實例。
實例代碼:
實例一:通過Service來遠程調用一個接口子類的函數方法
功能描述:在MainActivity中通過綁定MyService服務類,來遠程調用MyPlayer(實現了IPlayer接口)的方法過程。需要定義一個IPlayer.aidl文件,ADT工具會自動生成一個IPlayer接口類,然後再由MyPlayer繼承IPlayer接口類中的靜態內部抽像類,實現接口方法,進而供其它應用程序遠程調用。(在本例中為了方便,MainActivity與MyService類同處一個應用程序中,實現運用時,可以不在同一個應用程序中,只要有權限訪問MyService服務,就能得到IPlayer接口,進而執行該接口實例方法)
程序清單:IPlayer.aidl
  1. package com.magc.rpc;

  2. interface IPlayer
  3. {

  4.     void setName(String name);
  5.     void addFile(String f_name);
  6.     String ToString();
  7. }
複製代碼
程序清單:IPlayer.java (ADT根據上面IPlayer.aidl文件自動生成,不能編輯該文件)


  1. /*
  2. * This file is auto-generated. DO NOT MODIFY.
  3. * Original file: F:\\work\\Android_App\\MyRPCService\\src\\com\\magc\\rpc\\IPlayer.aidl
  4. */
  5. package com .magc.rpc;
  6. public  interface IPlayer extends android.os.IInterface
  7. {
  8. /** Local-side IPC implementation stub class. */
  9. public  static  abstract  class Stub extends android.os.Binder implements com.magc.rpc.IPlayer
  10. {
  11. private  static  final java.lang.String DESCRIPTOR =  " com.magc.rpc.IPlayer " ;
  12. /** Construct the stub at attach it to the interface. */
  13. public Stub()
  14. {
  15. this .attachInterface( this , DESCRIPTOR);
  16. }
  17. /* *
  18. * Cast an IBinder object into an com.magc.rpc.IPlayer interface,
  19. * generating a proxy if needed.
  20. */
  21. public  static com.magc.rpc.IPlayer asInterface(android.os.IBinder obj)
  22. {
  23. if ((obj = = null )) {
  24. return  null ;
  25. }
  26. android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
  27. if (((iin != null ) && (iin instanceof com.magc.rpc.IPlayer ))) {
  28. return ((com.magc.rpc.IPlayer)iin);
  29. }
  30. return  new com.magc.rpc.IPlayer.Stub.Proxy(obj);
  31. }
  32. public android.os.IBinder asBinder()
  33. {
  34. return  this ;
  35. }
  36. @Override public  boolean onTransact( int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
  37. {
  38. switch (code)
  39. {
  40. case INTERFACE_TRANSACTION:
  41. {
  42. reply.writeString(DESCRIPTOR);
  43. return  true ;
  44. }
  45. case TRANSACTION_setName:
  46. {
  47. data.enforceInterface(DESCRIPTOR);
  48. java.lang.String _arg0;
  49. _arg0 = data.readString();
  50. this .setName(_arg0);
  51. reply.writeNoException();
  52. return  true ;
  53. }
  54. case TRANSACTION_addFile:
  55. {
  56. data.enforceInterface(DESCRIPTOR);
  57. java.lang.String _arg0;
  58. _arg0 = data.readString();
  59. this .addFile(_arg0);
  60. reply.writeNoException();
  61. return  true ;
  62. }
  63. case TRANSACTION_ToString:
  64. {
  65. data.enforceInterface(DESCRIPTOR) ;
  66. java.lang.String _result =  this .ToString();
  67. reply.writeNoException();
  68. reply.writeString(_result);
  69. return  true ;
  70. }
  71. }
  72. return  super .onTransact(code, data, reply, flags);
  73. }
  74. private  static  class Proxy implements com.magc.rpc.IPlayer
  75. {
  76. private android.os.IBinder mRemote;
  77. Proxy(android.os.IBinder remote)
  78. {
  79. mRemote = remote;
  80. }
  81. public android.os.IBinder asBinder()
  82. {
  83. return mRemote;
  84. }
  85. public java. lang.String getInterfaceDescriptor()
  86. {
  87. return DESCRIPTOR;
  88. }
  89. public  void setName(java.lang.String name) throws android.os.RemoteException
  90. {
  91. android.os.Parcel _data = android.os.Parcel.obtain();
  92. android.os. Parcel _reply = android.os.Parcel.obtain();
  93. try {
  94. _data.writeInterfaceToken(DESCRIPTOR);
  95. _data.writeString(name);
  96. mRemote.transact(Stub.TRANSACTION_setName, _data, _reply, 0 );
  97. _reply.readException();
  98. }
  99. finally {
  100. _reply.recycle();
  101. _data.recycle();
  102. }
  103. }
  104. public  void addFile(java.lang.String f_name) throws android.os.RemoteException
  105. {
  106. android.os.Parcel _data = android.os.Parcel.obtain( );
  107. android.os.Parcel _reply = android.os.Parcel.obtain();
  108. try {
  109. _data.writeInterfaceToken(DESCRIPTOR);
  110. _data.writeString(f_name);
  111. mRemote.transact(Stub.TRANSACTION_addFile, _data, _reply, 0 );
  112. _reply.readException();
  113. }
  114. finally {
  115. _reply.recycle();
  116. _data.recycle();
  117. }
  118. }
  119. public java.lang.String ToString() throws android.os.RemoteException
  120. {
  121. android.os.Parcel _data = android.os. Parcel.obtain();
  122. android.os.Parcel _reply = android.os.Parcel.obtain();
  123. java.lang.String _result;
  124. try {
  125. _data.writeInterfaceToken(DESCRIPTOR);
  126. mRemote.transact(Stub.TRANSACTION_ToString, _data, _reply , 0 );
  127. _reply.readException();
  128. _result = _reply.readString();
  129. }
  130. finally {
  131. _reply.recycle();
  132. _data.recycle();
  133. }
  134. return _result;
  135. }
  136. }
  137. static  final  int TRANSACTION_setName = (android.os.IBinder .FIRST_CALL_TRANSACTION +  0 );
  138. static  final  int TRANSACTION_addFile = (android.os.IBinder.FIRST_CALL_TRANSACTION +  1 );
  139. static  final  int TRANSACTION_ToString = (android.os.IBinder.FIRST_CALL_TRANSACTION +  2 );
  140. }
  141. public  void setName(java.lang.String name) throws android.os.RemoteException;
  142. public  void addFile(java.lang.String f_name) throws android.os.RemoteException;
  143. public java.lang.String ToString() throws android.os.RemoteException;
  144. }
複製代碼


程序清單:MyPlayer.java (實現IPlayer的靜態內部抽像類Stub)

  1. package com.magc.rpc;

  2. import android.os.RemoteException;
  3. import android.util.Log;

  4. import com.magc.rpc.IPlayer.Stub;
  5. /**
  6. *
  7. * @author magc
  8. *實現IPlayer接口類中的靜態內部抽象類,即實現IPlayer接口方法
  9. *將來供其它應用程序遠程調用執行方法
  10. */
  11. public  class MyPlayer extends Stub {

  12.     private String name = "" ;
  13.     @Override
  14.     public  void addFile(String fName) throws RemoteException {         System.out.println(
  15.         
  16. " add file ... " );     }     @Override




  17.     public  void setName(String name) throws RemoteException {

  18.         this .name = name;
  19.         Log.i( " magc " , " setName-- " + name);
  20.     }
  21.    
  22.     public String ToString( )
  23.     {
  24.         String str =  " MyPlayer-- " + name;
  25.         Log.i( " magc " , " MyPlayer-- " + name);
  26.         return str;
  27.     } }
複製代碼
程序清單:MyService.java (一個Service類,供其它程序來遠程綁定,返回IPlayer接口)


  1. package com.magc.rpc;

  2. import com.magc.rpc.IPlayer.Stub;

  3. import android.app.Service;
  4. import android.content.Intent;
  5. import android.os.IBinder;


  6. /**
  7. *
  8. * @author magc
  9. *此服務類作為一個代理角色,供其它應用程序綁定,並返回接口實例
  10. *
  11. *可看作是代理模式的應用
  12. */
  13. public  class MyService extends Service {

  14.     private Stub player =  new MyPlayer();
  15.     @Override
  16.     public IBinder onBind( Intent arg0) {
  17.         return player;
  18.     }     @Override


  19.     public  void onCreate() {
  20.         super .onCreate();
  21.     } }
複製代碼
程序清單:MainActivity.java (作為客戶端遠程調用IPlayer接口方法)

  1. <? xml version="1.0" encoding="utf-8" ?>
  2. < manifest xmlns:android ="http://schemas.android.com/apk/res/android"
  3.       package ="com.magc.rpc"
  4.       android :versionCode ="1"
  5.       android:versionName ="1.0" >
  6.     < uses-sdk android:minSdkVersion ="9"  />

  7.     < application android:icon ="@drawable/icon" android:label ="@string/app_name" >
  8.         < activity android:name =".MainActivity"
  9.                   android:label ="@string/app_name" >
  10.             < intent-filter >
  11.                 < action android:name ="android.intent.action.MAIN"  />
  12.                 < category android:name =" android.intent.category.LAUNCHER"  />
  13.             </ intent-filter >
  14.         </ activity >

  15.         < service android:name =".MyService" >
  16.         < intent-filter >
  17.         < action android:name ="com.magc.rpc.action .MYSERVICE"  />
  18.         < category android:name ="android.intent.category.DEFAULT"  />
  19.         </ intent-filter >
  20.         </ service >
  21.     </ application >
  22. </ manifest >
複製代碼
上面Android應用程序運行後結果如下所示:
3.png
4.png
小結:
1、重點理解Android中對AIDL文件的定義,以及理解ADT工具自動生成的接口類IPlayer,特別是它的靜態內部類Stub以及Stub的asInterface方法,

2、Service作為一個代理角色,在其它應用程序通過Stub類的asInterface方法在綁定到一個服務時才能實現返回該接口實例,進而對該實例進行相關操作。


待續


轉帖 http://www.cnblogs.com/mandroid/archive/2011/02/26/1965428.html


 

臉書網友討論
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2016-12-11 08:42 , Processed in 0.084541 second(s), 25 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表