|
理解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接口方法)
- <? 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/mandroid/archive/2011/02/26/1965428.html
|
|