woff 發表於 2014-11-25 00:01:49

理解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;
publicinterface IPlayer extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
publicstaticabstractclass Stub extends android.os.Binder implements com.magc.rpc.IPlayer
{
privatestaticfinal 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.
*/
publicstatic com.magc.rpc.IPlayer asInterface(android.os.IBinder obj)
{
if ((obj = = null )) {
returnnull ;
}
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);
}
returnnew com.magc.rpc.IPlayer.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
returnthis ;
}
@Override publicboolean 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);
returntrue ;
}
case TRANSACTION_setName:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this .setName(_arg0);
reply.writeNoException();
returntrue ;
}
case TRANSACTION_addFile:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this .addFile(_arg0);
reply.writeNoException();
returntrue ;
}
case TRANSACTION_ToString:
{
data.enforceInterface(DESCRIPTOR) ;
java.lang.String _result =this .ToString();
reply.writeNoException();
reply.writeString(_result);
returntrue ;
}
}
returnsuper .onTransact(code, data, reply, flags);
}
privatestaticclass 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;
}
publicvoid 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();
}
}
publicvoid 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;
}
}
staticfinalint TRANSACTION_setName = (android.os.IBinder .FIRST_CALL_TRANSACTION +0 );
staticfinalint TRANSACTION_addFile = (android.os.IBinder.FIRST_CALL_TRANSACTION +1 );
staticfinalint TRANSACTION_ToString = (android.os.IBinder.FIRST_CALL_TRANSACTION +2 );
}
publicvoid setName(java.lang.String name) throws android.os.RemoteException;
publicvoid 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接口方法
*將來供其它應用程序遠程調用執行方法
*/
publicclass MyPlayer extends Stub {

    private String name = "" ;
    @Override
    publicvoid addFile(String fName) throws RemoteException {         System.out.println(
      
" add file ... " );   }   @Override




    publicvoid 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
*此服務類作為一個代理角色,供其它應用程序綁定,並返回接口實例
*
*可看作是代理模式的應用
*/
publicclass MyService extends Service {

    private Stub player =new MyPlayer();
    @Override
    public IBinder onBind( Intent arg0) {
      return player;
    }   @Override


    publicvoid 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

頁: [1]
查看完整版本: 理解Android系統的進程間通信原理(二)----RPC機制