Android开发 - IInterface 接口 Binder 机制跨进程通信 (IPC)解析

什么是 IInterface

  • IInterface 一个接口,用于跨进程通信 (IPC)。有时需要让一个应用程序与另一个应用程序服务进行通信。这些应用程序可能运行在不同的进程中,使用 Binder 机制来实现这种通信,而 IInterface 就是 Binder 机制一部分

  • 简单来说,IInterface 是一个基础接口,它为跨进程通信提供了一个通用的接口

为什么需要 IInterface

  • 每个应用程序通常运行在自己的进程中。由于进程的隔离特性,一个进程中的代码无法直接访问另一个进程中的对象。为了让不同进程之间能够安全地互相通信,由此使用了 Binder 机制
    • 跨进程通信 (IPC)IInterface 是一个基础接口,允许不同进程之间进行方法调用(即所谓的远程过程调用,RPC)
    • AIDL (Android Interface Definition Language):当使用 AIDL 创建跨进程接口时,系统会自动生成一个接口,该接口继承IInterface。这个接口用来定义客户端如何与服务端进行通信

IInterface 的主要方法

  • asBinder():这个方法返回一个 IBinder 对象IBinderBinder 通信核心对象,它允许客户端获取一个用于与服务端通信Binder 对象。每当实现一个 AIDL 接口自定义的 Binder 类时,你都需要实现 asBinder() 方法,返回一个能够处理远程请求IBinder 对象

IInterface 的使用场景

  • IInterface 通常不会直接使用,而是通过 AIDL 或者其他 Binder 类间接使用。以下是几个常见使用场景
    • AIDL 文件生成的接口:当开发者使用 AIDL 定义接口时,会自动生成一个 Java 接口,这个接口会继承自 IInterface。这个接口提供了客户端与服务端通信方法
    • 自定义 Binder 类:如果开发者需要更灵活跨进程通信控制,也可以手动实现一个 Binder 类,该也会间接实现 IInterface,并提供 asBinder() 方法

代码示例(一)

  • 接下来定义一个简单的服务 MyService,它提供一个方法 getMessage(),返回一条字符串消息。客户端可以通过绑定到这个服务调用该方法获取消息

    1. 定义一个 AIDL 文件:创建一个 AIDL 文件 IMyService.aidl,定义服务接口

      // IMyService.aidl
      package com.example.myservice;
      
      // AIDL接口定义,继承自IInterface
      interface IMyService {
          // 定义一个远程方法,用于获取消息
          String getMessage();
      }
      
    2. 系统生成接口:编译 AIDL 文件后,系统会生成一个 Java 接口 IMyService,该接口继承自 IInterface(以下并非创建的类,只做讲解,理解即可)

      // IMyService.java
      package com.example.myservice;
      
      // IMyService 接口继承自 IInterface,表示它是一个用于跨进程通信的接口
      public interface IMyService extends android.os.IInterface {
          // Stub 类,负责实现 Binder 相关的逻辑
          // Stub 是 IMyService 的抽象类,它继承自 Binder 并实现 IMyService 接口。它用于处理 IPC 相关的细节
          public static abstract class Stub extends android.os.Binder implements IMyService {
              // Stub 的构造方法
              public Stub() {
                  // 调用 attachInterface 方法将自己附加到接口上
                  this.attachInterface(this, DESCRIPTOR);
              }
      
              // 静态方法 asInterface 用于将 IBinder 对象转换为 IMyService 接口,方便客户端使用
              public static IMyService asInterface(android.os.IBinder obj) {
                  if ((obj == null)) {
                      return null;
                  }
                  IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                  if (((iin != null) && (iin instanceof IMyService))) {
                      return ((IMyService) iin);
                  }
                  return new Proxy(obj);
              }
      
              // 重写 asBinder 方法,返回当前的 Binder 对象,以便客户端和服务端通信
              @Override
              public android.os.IBinder asBinder() {
                  return this;
              }
      
              // 代理类,用于客户端的IPC调用
              // Proxy 类用于实现客户端的代理。它持有一个 IBinder 对象,并通过它与服务端通信
              private static class Proxy implements IMyService {
                  private android.os.IBinder mRemote;
      
                  // Proxy 类的构造方法,接收一个 IBinder 对象,并将其保存为 mRemote
                  Proxy(android.os.IBinder remote) {
                      mRemote = remote;
                  }
      
                  @Override
                  public android.os.IBinder asBinder() {
                      return mRemote;
                  }
      
                  // 在 Proxy 类中实现 getMessage 方法,通过 IBinder 进行远程调用
                  @Override
                  public String getMessage() throws android.os.RemoteException {
                      // 创建一个 Parcel 对象 _data,用于封装数据
                      android.os.Parcel _data = android.os.Parcel.obtain();
                      android.os.Parcel _reply = android.os.Parcel.obtain();
                      String _result;
                      try {
                          _data.writeInterfaceToken(DESCRIPTOR);
                          // 通过 transact 方法向服务端发送请求
                          mRemote.transact(Stub.TRANSACTION_getMessage, _data, _reply, 0);
                          // 读取服务端的返回结果
                          _reply.readException();
                          // 并将其转换为字符串
                          _result = _reply.readString();
                      } finally {
                          _reply.recycle();
                          _data.recycle();
                      }
                      return _result;
                  }
              }
      
              // 方法标识符
              static final int TRANSACTION_getMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
      
              // 在 Stub 类中实现 getMessage 方法,处理客户端的请求并返回消息
              @Override
              public android.os.ParcelFileDescriptor getMessage(android.os.ParcelFileDescriptor data) throws android.os.RemoteException {
                  // 服务端实际实现 getMessage 方法
                  data.enforceInterface(DESCRIPTOR);
                  String _result = this.getMessage();
                  data.writeNoException();
                  // 将返回的消息写入到 Parcel 中,发送回客户端
                  data.writeString(_result);
                  return data;
              }
          }
      
          // 服务端需要实现的实际方法
          public String getMessage() throws android.os.RemoteException;
      }
      
    3. 服务端实现:服务端将实现这个生成的接口,并提供具体业务逻辑

      // MyService.java
      package com.example.myservice;
      
      import android.app.Service;
      import android.content.Intent;
      import android.os.IBinder;
      import android.os.RemoteException;
      
      // 实现IMyService接口的服务类
      public class MyService extends Service {
      
          // 实现AIDL接口的Stub类
          private final IMyService.Stub mBinder = new IMyService.Stub() {
              @Override
              public String getMessage() throws RemoteException {
                  // 服务端实现的具体逻辑,返回一条消息
                  return "Hello from MyService!";
              }
          };
      
          @Override
          public IBinder onBind(Intent intent) {
              // 返回Stub实例,以便客户端绑定
              return mBinder;
          }
      }
      
    4. 客户端调用:客户端可以绑定到 MyService 并调用远程方法

      // MainActivity.java
      package com.example.myservice;
      
      import android.content.ComponentName;
      import android.content.Context;
      import android.content.Intent;
      import android.content.ServiceConnection;
      import android.os.IBinder;
      import android.os.RemoteException;
      import android.widget.TextView;
      import androidx.appcompat.app.AppCompatActivity;
      import android.os.Bundle;
      
      public class MainActivity extends AppCompatActivity {
      
          // 声明一个 IMyService 对象,用于保存绑定的服务
          private IMyService mService;
          // 一个布尔变量 mBound,用于跟踪服务是否绑定
          private boolean mBound = false;
      
          // 定义 ServiceConnection,用于管理服务连接的回调
          private ServiceConnection mConnection = new ServiceConnection() {
              // 当服务连接时被调用,传递 IBinder 对象
              @Override
              public void onServiceConnected(ComponentName className, IBinder service) {
                  // 获取绑定的服务
                  mService = IMyService.Stub.asInterface(service);
                  mBound = true;
                  try {
                      // 调用远程方法并显示结果
                      String message = mService.getMessage();
                      ((TextView) findViewById(R.id.textView)).setText(message);
                  } catch (RemoteException e) {
                      e.printStackTrace();
                  }
              }
      
              // // 当服务断开时被调用
              @Override
              public void onServiceDisconnected(ComponentName arg0) {
                  mService = null;
                  mBound = false;
              }
          };
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
          }
      
          @Override
          protected void onStart() {
              super.onStart();
              // 绑定服务
              Intent intent = new Intent(this, MyService.class);
              bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
          }
      
          @Override
          protected void onStop() {
              super.onStop();
              // 解除绑定服务
              if (mBound) {
                  unbindService(mConnection);
                  mBound = false;
              }
          }
      }
      
      

总结(一)

  • 以上示例,IInterface 用于实现跨进程通信的一个基础接口,它提供了远程过程调用基础框架。虽然你可能不会直接使用 IInterface,但它是所有 AIDL自定义 Binder 通信核心概念

代码示例(二)

  • 接下来将实现一个简单的服务 MyService,它运行在一个独立的进程中,并提供一个接口 IMyService 供客户端调用。客户端可以通过这个接口调用服务端方法

    1. 创建 AIDL 文件:需要定义一个 AIDL 文件 IMyService.aidl,它定义了服务接口

      // IMyService.aidl
      package com.example.myservice;
      
      // 定义一个 AIDL 接口,所有方法都将是远程调用的
      interface IMyService {
          // 一个简单的计算两个整数和的方法
          int add(int a, int b);
      }
      
    2. AIDL 文件生成的接口编译 IMyService.aidl 文件后,系统会生成一个 Java 接口 IMyService。这个接口继承自 android.os.IInterface,并提供了所有定义在 AIDL 文件中方法非创建的类这里就不复述

    3. 实现服务端的 Binder 类:服务端实现 AIDL 生成的接口,并通过一个 Binder 类提供具体方法逻辑

      // MyService.java
      package com.example.myservice;
      
      import android.app.Service;
      import android.content.Intent;
      import android.os.IBinder;
      import android.os.RemoteException;
      
      // 继承自 Service 类,提供一个 AIDL 接口实现
      // 定义一个服务 MyService,它继承自 Service 类。服务是一个运行在后台的组件,可以执行长时间运行的操作
      public class MyService extends Service {
      
          // 实现 AIDL 生成的接口 IMyService.Stub
          // 创建一个 IMyService.Stub 类型的对象 binder。IMyService.Stub 是 AIDL 编译器生成的一个抽象类,它实现了 IInterface 接口
          private final IMyService.Stub binder = new IMyService.Stub() {
              // 实现 IMyService 接口中的 add 方法。该方法接收两个整数并返回它们的和
              @Override
              public int add(int a, int b) throws RemoteException {
                  // 实现接口中的 add 方法:计算两个整数的和
                  return a + b;
              }
          };
      
          // 重写 onBind 方法。当客户端绑定到服务时,系统调用这个方法
          @Override
          public IBinder onBind(Intent intent) {
              // 当客户端绑定到服务时,返回 binder 对象,以便客户端能够与服务进行通信
              return binder;
          }
      }
      
    4. 客户端代码示例:客户端代码绑定到服务调用远程方法

      // MainActivity.java
      package com.example.myserviceclient;
      
      import android.content.ComponentName;
      import android.content.Context;
      import android.content.Intent;
      import android.content.ServiceConnection;
      import android.os.Bundle;
      import android.os.IBinder;
      import android.os.RemoteException;
      import android.widget.TextView;
      import androidx.appcompat.app.AppCompatActivity;
      import com.example.myservice.IMyService;
      
      public class MainActivity extends AppCompatActivity {
      
          // 定义一个 IMyService 类型的变量,用于存储服务接口的引用
          private IMyService myService; // 定义 AIDL 接口类型的变量
          private boolean isBound = false; // 用于跟踪服务绑定状态
      
          // 创建一个 ServiceConnection 对象,用于处理服务连接和断开
          private ServiceConnection serviceConnection = new ServiceConnection() {
      
              // 当客户端成功绑定到服务时调用此方法
              @Override
              public void onServiceConnected(ComponentName name, IBinder service) {
                  // 服务连接时调用,将 IBinder 对象转换为 AIDL 接口
                  // 使用 IMyService.Stub.asInterface 方法将传递的 IBinder 对象转换为 IMyService 接口。这一步使客户端能够调用远程服务的方法
                  myService = IMyService.Stub.asInterface(service);
                  isBound = true;
                  // 调用远程服务方法
                  try {
                      // 调用远程服务方法 add,并传递两个整数。这个调用实际上是一个跨进程调用
                      int result = myService.add(5, 3);
                      TextView textView = findViewById(R.id.result_text);
                      // 显示服务返回的结果
                      textView.setText("Result from service: " + result);
                  } catch (RemoteException e) {
                      e.printStackTrace();
                  }
              }
      
              // 当服务意外断开时调用此方法
              @Override
              public void onServiceDisconnected(ComponentName name) {
                  // 服务断开时调用,清空接口实例并更新绑定状态
                  myService = null;
                  isBound = false;
              }
          };
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              // 启动并绑定远程服务:创建一个新的 Intent,用于绑定服务
              Intent intent = new Intent();
              // 设置 ComponentName,指定服务的包名和类名
              intent.setComponent(new ComponentName("com.example.myservice", "com.example.myservice.MyService"));
              // 绑定服务。BIND_AUTO_CREATE 标志表示如果服务尚未启动,则自动启动它
              bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
          }
      
          // 当活动销毁时调用,确保解绑服务以防止内存泄漏
          @Override
          protected void onDestroy() {
              super.onDestroy();
              // 解绑服务以防止内存泄漏
              if (isBound) {
                  unbindService(serviceConnection);
                  isBound = false;
              }
          }
      }
      

总结(二)

  • 以上示例,展示了如何使用 IInterface 及其衍生类(如通过 AIDL 定义的接口)实现应用程序中的跨进程通信。服务端实现了 AIDL 接口并提供了一个 Binder 对象。客户端通过 ServiceConnection 连接服务,并使用接口调用远程方法
posted @ 2024-08-27 21:20  阿俊学JAVA  阅读(301)  评论(0编辑  收藏  举报