Android开发 - IInterface 接口 Binder 机制跨进程通信 (IPC)解析
<h1 id="什么是-iinterface">什么是 IInterface</h1><ul>
<li>
<p><strong>IInterface</strong> 一个<strong>接口</strong>,用于<strong>跨进程通信 (IPC)</strong>。有时需要让<strong>一个应用程序与另一个应用程序</strong>或<strong>服务</strong>进行<strong>通信</strong>。这些应用程序可能<strong>运行在不同的进程</strong>中,使用 <strong>Binder 机制</strong>来实现这种<strong>通信</strong>,而 <strong>IInterface</strong> 就是 <strong>Binder 机制</strong>的<strong>一部分</strong></p>
</li>
<li>
<p>简单来说,<strong>IInterface</strong> 是一个<strong>基础接口</strong>,它为<strong>跨进程通信</strong>提供了一个<strong>通用的接口</strong></p>
</li>
</ul>
<h1 id="为什么需要-iinterface">为什么需要 IInterface</h1>
<ul>
<li><strong>每个应用程序通常运行在自己的进程中</strong>。由于进程的<strong>隔离</strong>特性,<strong>一个进程中的代码无法直接访问另一个进程中的对象</strong>。为了让<strong>不同进程之间</strong>能够<strong>安全地互相通信</strong>,由此使用了 <strong>Binder 机制</strong>
<ul>
<li><strong>跨进程通信 (IPC)</strong>:<strong>IInterface</strong> 是一个<strong>基础接口</strong>,允许<strong>不同进程之间</strong>进行<strong>方法调用(即所谓的远程过程调用,RPC)</strong></li>
<li><strong>AIDL (Android Interface Definition Language)</strong>:当使用 <strong>AIDL</strong> 创建<strong>跨进程接口</strong>时,系统会<strong>自动生成</strong>一个<strong>接口</strong>,该<strong>接口继承</strong>自 <strong>IInterface</strong>。这个<strong>接口</strong>用来<strong>定义客户端</strong>如何与<strong>服务端</strong>进行<strong>通信</strong></li>
</ul>
</li>
</ul>
<h1 id="iinterface-的主要方法">IInterface 的主要方法</h1>
<ul>
<li><strong><code>asBinder()</code></strong>:这个方法<strong>返回</strong>一个 <strong>IBinder 对象</strong>。<strong>IBinder</strong> 是 <strong>Binder 通信</strong>的<strong>核心对象</strong>,它允许<strong>客户端</strong>获取一个<strong>用于与服务端通信</strong>的 <strong>Binder 对象</strong>。每当实现一个 <strong>AIDL 接口</strong>或<strong>自定义的 Binder 类</strong>时,你都需要<strong>实现 <code>asBinder()</code> 方法</strong>,返回一个能够<strong>处理远程请求</strong>的 <strong>IBinder 对象</strong></li>
</ul>
<h1 id="iinterface-的使用场景">IInterface 的使用场景</h1>
<ul>
<li><strong>IInterface</strong> 通常不会<strong>直接使用</strong>,而是<strong>通过 AIDL</strong> 或者<strong>其他 Binder 类</strong>来<strong>间接使用</strong>。以下是几个<strong>常见</strong>的<strong>使用场景</strong>:
<ul>
<li><strong>AIDL 文件生成的接口</strong>:当开发者使用 <strong>AIDL 定义接口</strong>时,会<strong>自动生成</strong>一个 <strong>Java 接口</strong>,这个<strong>接口</strong>会继承自 <strong>IInterface</strong>。这个<strong>接口</strong>提供了<strong>客户端与服务端通信</strong>的<strong>方法</strong></li>
<li><strong>自定义 Binder 类</strong>:如果开发者需要<strong>更灵活</strong>的<strong>跨进程通信控制</strong>,也可以<strong>手动</strong>实现一个 <strong>Binder 类</strong>,该<strong>类</strong>也会<strong>间接实现 IInterface</strong>,并<strong>提供 <code>asBinder()</code> 方法</strong></li>
</ul>
</li>
</ul>
<h1 id="代码示例一">代码示例(一)</h1>
<ul>
<li>
<p>接下来定义一个<strong>简单的服务 MyService</strong>,它提供一个<strong>方法 <code>getMessage()</code></strong>,返回一条<strong>字符串</strong>消息。<strong>客户端</strong>可以<strong>通过绑定到这个服务</strong>并<strong>调用该方法</strong>来<strong>获取消息</strong>:</p>
<ol>
<li>
<p><strong>定义一个 AIDL 文件</strong>:创建一个 <strong>AIDL 文件 <code>IMyService.aidl</code></strong>,定义<strong>服务接口</strong></p>
<pre><code class="language-java">// IMyService.aidl
package com.example.myservice;
// AIDL接口定义,继承自IInterface
interface IMyService {
// 定义一个远程方法,用于获取消息
String getMessage();
}
</code></pre>
</li>
<li>
<p><strong>系统生成接口</strong>:编译 <strong>AIDL 文件</strong>后,系统会生成一个 <strong>Java 接口 IMyService</strong>,该<strong>接口</strong>继承自 <strong>IInterface(以下并非创建的类,只做讲解,理解即可)</strong></p>
<pre><code class="language-java">// 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;
}
</code></pre>
</li>
<li>
<p><strong>服务端实现</strong>:服务端将<strong>实现</strong>这个<strong>生成的接口</strong>,并提供<strong>具体</strong>的<strong>业务逻辑</strong></p>
<pre><code class="language-java">// 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;
}
}
</code></pre>
</li>
<li>
<p><strong>客户端调用</strong>:客户端可以<strong>绑定到 MyService</strong> 并调用<strong>远程</strong>方法</p>
<pre><code class="language-java">// 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;
}
}
}
</code></pre>
</li>
</ol>
</li>
</ul>
<h2 id="总结一"><strong>总结</strong>(一)</h2>
<ul>
<li>以上示例,<strong>IInterface</strong> 用于实现<strong>跨进程通信</strong>的一个<strong>基础接口</strong>,它提供了<strong>远程过程调用</strong>的<strong>基础框架</strong>。虽然你可能不会直接使用 <strong>IInterface</strong>,但它是<strong>所有 AIDL</strong> 和<strong>自定义 Binder 通信</strong>的<strong>核心概念</strong></li>
</ul>
<h1 id="代码示例二">代码示例(二)</h1>
<ul>
<li>
<p>接下来将实现一个<strong>简单的服务 MyService</strong>,它运行在一个<strong>独立的进程</strong>中,并提供一个<strong>接口 IMyService</strong> 供客户端调用。客户端可以<strong>通过这个接口调用服务端</strong>的<strong>方法</strong></p>
<ol>
<li>
<p><strong>创建 AIDL 文件</strong>:需要定义一个 <strong>AIDL 文件 <code>IMyService.aidl</code></strong>,它定义了<strong>服务接口</strong></p>
<pre><code class="language-java">// IMyService.aidl
package com.example.myservice;
// 定义一个 AIDL 接口,所有方法都将是远程调用的
interface IMyService {
// 一个简单的计算两个整数和的方法
int add(int a, int b);
}
</code></pre>
</li>
<li>
<p><strong>AIDL 文件生成的接口</strong>:<strong>编译 <code>IMyService.aidl</code> 文件后</strong>,系统会<strong>生成</strong>一个 <strong>Java 接口 IMyService</strong>。这个<strong>接口</strong>继承自 <strong><code>android.os.IInterface</code></strong>,并提供了<strong>所有定义在 AIDL 文件中</strong>的<strong>方法</strong>,<strong>非创建的类</strong>这里就<strong>不复述</strong>了</p>
</li>
<li>
<p><strong>实现服务端的 Binder 类</strong>:服务端实现 <strong>AIDL 生成的接口</strong>,并通过一个 <strong>Binder 类</strong>提供<strong>具体</strong>的<strong>方法逻辑</strong></p>
<pre><code class="language-java">// 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;
}
}
</code></pre>
</li>
<li>
<p><strong>客户端代码示例</strong>:客户端代码<strong>绑定到服务</strong>并<strong>调用远程方法</strong></p>
<pre><code class="language-java">// 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;
}
}
}
</code></pre>
</li>
</ol>
</li>
</ul>
<h2 id="总结二"><strong>总结</strong>(二)</h2>
<ul>
<li>以上示例,展示了<strong>如何使用 IInterface 及其衍生类(如通过 AIDL 定义的接口)</strong>实现应用程序中的<strong>跨进程通信</strong>。服务端实现了 <strong>AIDL 接口</strong>并提供了一个 <strong>Binder 对象</strong>。客户端通过 <strong>ServiceConnection 连接</strong>到<strong>服务</strong>,并使用<strong>接口</strong>调用<strong>远程方法</strong></li>
</ul><br><br>
来源:https://www.cnblogs.com/ajunjava/p/18383574
頁:
[1]