Android IPC 之 AIDL 使用

简介: 🔥 AIDL AIDL 全称 Android Interface Definition Language (Android 接口定义语言),允许你定义客户端和服务都同意的编程接口,以便使用进程间通信 (IPC) 相互通信。在Android上,一个进程不能正常访问另一个进程的内存,因此 Android 使用 AIDL 为你处理。

🔥 AIDL


       AIDL 全称 Android Interface Definition Language (Android 接口定义语言),允许你定义客户端和服务都同意的编程接口,以便使用进程间通信 (IPC) 相互通信。在Android上,一个进程不能正常访问另一个进程的内存,因此 Android 使用 AIDL 为你处理。


注意:仅当你允许来自不同应用程序的客户端访问你的 IPC 服务并希望在您的服务中处理多线程时,才需要使用 AIDL。 如果是多进程单线程那么使用 Messenger 就可以了。


🔥 名词解释


💥 方法


  • DESCRIPTOR:Binder的唯一标识,一般用当前的 Binder 的类名表示。


  • asInterface(IBinder obj):将服务端的 Binder对象生成客户端所需的AIDL接口类型对象,这种转换过程是区分进程的,如果位于同一进程,返回的就是Stub 对象本身,否则返回的是系统封装后的Stub.proxy对象。


  • asBinder:用于返回当前Binder对象。


  • onTransact:运行在服务端中的 Binder 线程池中,远程请求会通过系统底层封装后交由此方法来处理。


💥 tag


  • in:数据只能由客户端流向服务端,服务端将会收到客户端对象的完整数据,客户端对象不会因为服务端对传参的修改而发生变动。


  • out:数据只能由服务端流向客户端,服务端将会收到客户端对象,该对象不为空,但是它里面的字段为空,但是在服务端对该对象作任何修改之后客户端的传参对象都会同步改动。


  • inout:服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。


🔥 定义 AIDL 接口


要使用 AIDL ,请执行以下步骤:


  • 创建 .aidl 文件


  • 实现接口


  • 向客户端公开接口


💥 创建 .aidl 文件


       AIDL 使用一种简单的语法,你可以使用一个或多个可以接受参数和返回值的方法来声明一个接口。参数和返回值可以是任何类型,甚至是其他 AIDL 生成的接口。


      必须使用 Java 编程语言构建 .aidl 文件。每个 .aidl 文件必须定义一个接口,并且只需要接口声明和方法名。


AIDL 支持以下数据类型:


  • Java的所有原始类型(如 int )


  • 所有原始数组(如 int[])


  • String


  • CharSequence


  • List


  • Map


       如下:

微信图片_20220524114959.png


输入名称>finish


微信图片_20220524115023.png

  创建aidl


微信图片_20220524115045.png


  此时 在相同包名下创建.aidl 文件。


IUserInterface.aidl


// IUserInterface.aidl
package com.scc.demo.ipc;
// Declare any non-default types here with import statements
interface IUserInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}


  只需将 .aidl 文件保存在项目的 src/ 目录中,当你构建应用程序时,SDK 工具会在项目的 gen/ 目录中生成 IBinder 接口文件。 生成的文件名与 .aidl 文件名匹配,但具有 .java 扩展名(例如,IUserInterface.aidl 结果为 IUserInterface.java)。


       如果你使用 Android Studio,增量构建几乎会立即生成绑定器类。如下图:


微信图片_20220524115202.png


就问你6不6。


💥 Implement the interface


       构建应用程序时,Android SDK 工具会生成一个以 .aidl 文件命名的 .java 接口文件。 生成的接口包括一个名为 Stub 的子类,它是其父接口(例如,IUserInterface.Stub)的抽象实现,并声明了 .aidl 文件中的所有方法 (如上图)。


注意:Stub 还定义了一些辅助方法,最显着的是 asInterface(),它接受一个 IBinder(通常是传递给客户端的 onServiceConnected() 回调方法的那个)并返回一个 stub 接口的实例。


       因为咱使用的是 Android Studio ,构建的时候已经帮咱生成好了。


package com.scc.demo.ipc;
public interface IUserInterface extends android.os.IInterface
{
  public static class Default implements com.scc.demo.ipc.IUserInterface
  {
    @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.scc.demo.ipc.IUserInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.scc.demo.ipc.IUserInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    public static com.scc.demo.ipc.IUserInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.scc.demo.ipc.IUserInterface))) {
        return ((com.scc.demo.ipc.IUserInterface)iin);
      }
      return new com.scc.demo.ipc.IUserInterface.Stub.Proxy(obj);
    }
    @Override 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
    {
      ...
    }
    private static class Proxy implements com.scc.demo.ipc.IUserInterface
    {
      ...
    }
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public static boolean setDefaultImpl(com.scc.demo.ipc.IUserInterface impl) {
      ...
    }
    public static com.scc.demo.ipc.IUserInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}


💥 向客户端公开接口


       既然你服务端的接口已经定义好了,那就公开给客户端。要不客户端怎么调用。


public class AIDLService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //返回你的接口
        return stub;
    }
    private IUserInterface.Stub stub = new IUserInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            //你的逻辑
        }
    };
}


 好了,解释完了。上手搞。


🔥 实例


💥 User.java


       创建一个实例并进行序列化。具体过程就不描述了。


public class User implements Parcelable {
    String name;
    int age;
    ...
}


💥 IUserInterface.aidl


// IUserInterface.aidl
package com.scc.demo.ipc;
// Declare any non-default types here with import statements
parcelable User;
interface IUserInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    void setUser(in User user);
    User getUser();
}


💥 AIDLService.java


public class AIDLService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //返回你的接口
        return stub;
    }
    private IUserInterface.Stub stub = new IUserInterface.Stub() {
        User user = null;
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
        }
        @Override
        public void setUser(User user) throws RemoteException {
            this.user = user;
            MLog.e("AIDLService:"+user.toString());
        }
        @Override
        public User getUser() throws RemoteException {
            return user;
        }
    };
}


别忘记在AndroidMainfest.xml中声明一下。


💥 MainActivity


1.public class MainActivity extends ActivityBase implements View.OnClickListener {
    IUserInterface iUserInterface ;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
    }
    ServiceConnection connectionAidl = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iUserInterface = IUserInterface.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            bound = false;
        }
    };
    @Override
    protected void onStop() {
        super.onStop();
        if (bound) {
            unbindService(connectionAidl);
            bound = false;
        }
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_bind_service:
                bindService(new Intent(MainActivity.this, AIDLService.class),connectionAidl, Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_setuser:
                try {
                    iUserInterface.setUser(new User("Scc",15));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.btn_getuser:
                try {
                    User userG = iUserInterface.getUser();
                    MLog.e("MainActivity:"+userG.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
}



💥 运行效果


微信图片_20220524115720.png


进程也跨了,数据也拿到了,洗洗睡吧。


相关文章
|
8月前
|
编解码 前端开发 Android开发
如何让Android平台像IPC一样实现GB28181前端设备接入
好多开发者在做国标对接的时候,首先想到的是IPC摄像头,通过参数化配置,接入到国标平台,实现媒体数据的按需查看等操作。
|
20天前
|
安全 Java 定位技术
Android 浅度解析:AIDL & Binder (1)
Android 浅度解析:AIDL & Binder (1)
40 0
|
6天前
|
Android开发
Android AIDL 的使用
Android AIDL 的使用
14 1
|
3月前
|
Java Android开发
[Android AIDL] --- AIDL工程搭建
[Android AIDL] --- AIDL工程搭建
22 0
|
3月前
|
Java 开发工具 Android开发
[Android AIDL] --- AIDL原理简析
[Android AIDL] --- AIDL原理简析
37 0
|
8月前
|
编解码 开发工具 Android开发
如何在Android端实现轻量级RTSP服务(类似于IPC)
首先声明一点,本blog提到的轻量级RTSP服务,类似于网络摄像头(IPC),而非传统意义的接受外部推流的RTSP服务器。
467 0
|
10月前
|
缓存 Android开发