• 理解Android系统的进程间通信原理(二)----RPC机制


    理解Android系统中的轻量级解决方案RPC的原理,需要先回顾一下JAVA中的RMI(Remote Method Invocation)这个易于使用的纯JAVA方案(用来实现分布式应用)。有关RMI的相关知识,可以通过下图来归纳:

    RMI原理 (2)
    Android中的RPC也是参考了JAVA中的RMI方案,这里我们再详细了解一下RPC的实现过程。
    Android中的RPC机制是为了实现一个进程使用另一个进程中的远程对象,它使用了Android自己的AIDL(接口定义语言),使用户很方便地定义出一个接口作为规范,通过一个远程Service为代理 ,客户端在绑定该远程Service过程中获取远程对象,进而使用该对象。可参考下图所示:
    Android的RPC原理及应用 (2)
    补充: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接口方法)
    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接口方法
    *
    */
    publicclass MainActivity extends Activity {
    private String ACTION="com.magc.rpc.action.MYSERVICE";
    private IPlayer player;
    /** Called when the activity is first created. */
    @Override
    publicvoid 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
    publicvoid onServiceDisconnected(ComponentName name) {

    }

    /**
    * 绑定MyService服务后,返回IPlayer接口,进而调用该接口方法
    */
    @Override
    publicvoid 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方法在绑定到一个服务时才能实现返回该接口实例,进而对该实例进行相关操作。
     
     
    待续
     
     
  • 相关阅读:
    1461. Check If a String Contains All Binary Codes of Size K
    1460. Make Two Arrays Equal by Reversing Sub-arrays
    1466. Reorder Routes to Make All Paths Lead to the City Zero
    1464. Maximum Product of Two Elements in an Array
    js 获取select的值 / js动态给select赋值【转】
    js在HTML中的三种写法【转】
    php中 elseif和else if 的区别【转】
    PhpStorm 常用快捷键
    PhpStorm 2018最新汉化包 解决”设置”不可用问题【转】
    PHP json_encode里面经常用到的 JSON_UNESCAPED_UNICODE和JSON_UNESCAPED_SLASHES【转】
  • 原文地址:https://www.cnblogs.com/Jack-Lu/p/3179733.html
Copyright © 2020-2023  润新知