[Android AIDL] --- AIDL原理简析

这篇具有很好参考价值的文章主要介绍了[Android AIDL] --- AIDL原理简析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上一篇文章已经讲述了如何在Android studio中搭建基于aidl的cs模型框架,只是用起来了,这次对aidl及cs端如何调用的原理进行简单分析

1 创建AIDL文件

AIDL 文件可以分为两类。
一类是用来定义接口方法,声明要暴露哪些接口给客户端调用;
一类用来声明实现了 Parcelable 接口的数据类型,以供其他 AIDL 文件使用那些非默认支持的数据类型。
在 AIDL 文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下。
默认情况下,AIDL 支持下列数据类型:

八种基本数据类型:byte、charshortintlongfloatdouble、boolean
String,CharSequence
List类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

客户端和服务端都需要创建,我们先在server端中创建,然后复制到client端即可。在 Android Studio 中右键点击新建一个 AIDL 文件,如图所示:
[Android AIDL] --- AIDL原理简析,Android,android
创建完成后,系统就会默认创建一个 aidl 文件夹,文件夹下的目录结构即是工程的包名,AIDL 文件就在其中。如图所示:
[Android AIDL] --- AIDL原理简析,Android,android
文件中会有一个默认方法,可以删除掉,也可以新增其他方法。

2 实现接口

创建或修改过 AIDL 文件后需要 build 下工程,Android SDK 工具会生成以 .aidl 文件命名的 .java 接口文件(例如,IRemoteService.aidl 生成的文件名是 IRemoteService.java),在进程间通信中真正起作用的就是该文件。生成的接口包含一个名为 Stub 的子类(例如,IRemoteService.Stub),该子类是其父接口的抽象实现,并且会声明 AIDL 文件中的所有方法。
如要实现 AIDL 生成的接口,请实例化生成的 Binder 子类(例如,IRemoteService.Stub),并实现继承自 AIDL 文件的方法。
以下是使用匿名内部类实现 IRemoteService 接口的示例:

private final IRemoteService.Stub binder = new IRemoteService.Stub() {
    public int getPid(){
        return Process.myPid();
    }
    public void basicTypes(int anInt, long aLong, boolean aBoolean,
        float aFloat, double aDouble, String aString) {
        // Does nothing
    }
};

现在,binder 是 Stub 类的一个实例(一个 Binder),其定义了服务端的 RPC 接口。

3 server端公开接口

在为服务端实现接口后,需要向客户端公开该接口,以便客户端进行绑定。创建 Service 并实现 onBind(),从而返回生成的 Stub 的类实例。以下是服务端的示例代码:

public class RemoteService extends Service {
    private final String TAG = "RemoteService";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Return the interface
        Log.d(TAG, "onBind");
        return binder;
    }

    private final IRemoteService.Stub binder = new IRemoteService.Stub() {
        public int getPid() {
            return Process.myPid();
        }

        public void basicTypes(int anInt, long aLong, boolean aBoolean,
                               float aFloat, double aDouble, String aString) {
            Log.d(TAG, "basicTypes anInt:" + anInt + ";aLong:" + aLong + ";aBoolean:" + aBoolean + ";aFloat:" + aFloat + ";aDouble:" + aDouble + ";aString:" + aString);
        }
    };
}

我们还需要在 Manefest 文件中注册我们创建的这个 Service,否则客户端无法绑定服务。

      <service
            android:name=".RemoteService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

4 client 端调用IPC方法

当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务端的 onBind() 方法所返回的 binder 实例。
客户端还必须拥有接口类的访问权限,因此如果客户端和服务端在不同应用内,则客户端应用的 src/ 目录内必须包含 .aidl 文件(该文件会生成 android.os.Binder 接口,进而为客户端提供 AIDL 方法的访问权限)的副本。所以我们需要把服务端的 aidl 文件夹整个复制到客户端的 java 文件夹同个层级下,不需要改动任何代码。
当客户端在 onServiceConnected() 回调中收到 IBinder 时,它必须调用 IRemoteService.Stub.asInterface(service),以将返回的参数转换成 IRemoteService 类型。例如:

IRemoteService iRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Following the example above for an AIDL interface,
        // this gets an instance of the IRemoteInterface, which we can use to call on the service
        iRemoteService = IRemoteService.Stub.asInterface(service);
    }

    // Called when the connection with the service disconnects unexpectedly
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "Service has unexpectedly disconnected");
        iRemoteService = null;
    }
};

获得了 iRemoteService 对象,我们就可以调用 AIDL 中定义的方法了。如要断开连接,可以调用unbindService() 方法。以下是客户端的示例代码:

public class MainActivity extends AppCompatActivity {
    private final String TAG = "ClientActivity";
    private IRemoteService iRemoteService;
    private Button mBindServiceButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBindServiceButton = findViewById(R.id.btn_bind_service);
        mBindServiceButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String text = mBindServiceButton.getText().toString();
                if ("Bind Service".equals(text)) {
                    Intent intent = new Intent();
                    intent.setAction("com.example.aidl");
                    intent.setPackage("com.example.aidl.server");
                    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                } else {
                    unbindService(mConnection);
                    mBindServiceButton.setText("Bind Service");
                }
            }
        });
    }

    ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected");
            iRemoteService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
            iRemoteService = IRemoteService.Stub.asInterface(service);
            try {
                int pid = iRemoteService.getPid();
                int currentPid = Process.myPid();
                Log.d(TAG, "currentPID: " + currentPid + ", remotePID: " + pid);
                iRemoteService.basicTypes(12, 123, true, 123.4f, 123.45,
                        "服务端你好,我是客户端");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mBindServiceButton.setText("Unbind Service");
        }
    };
}

5 通过IPC传递对象

除了上面默认支持的数据类型,AIDL 还可以传递对象,但是该类必须实现 Parcelable 接口。而该类是两个应用间都需要使用到的,所以也需要在 AIDL 文件中声明该类,为了避免出现类名重复导致无法创建 AIDL 文件的错误,这里需要先创建 AIDL 文件,之后再创建类。
先在服务端新建一个 AIDL 文件,比如 Rect.aidl,示例如下:

// Rect.aidl
package com.example.aidl.server;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;

然后就可以创建 Rect 类了,并使之实现 Parcelable 接口。示例代码如下:

public class Rect implements Parcelable {
    private int left;
    private int top;
    private int right;
    private int bottom;

    public Rect(int left, int top, int right, int bottom) {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }

    public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
        public Rect createFromParcel(Parcel in) {
            return new Rect(in);
        }

        public Rect[] newArray(int size) {
            return new Rect[size];
        }
    };

    private Rect(Parcel in) {
        readFromParcel(in);
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(left);
        out.writeInt(top);
        out.writeInt(right);
        out.writeInt(bottom);
    }

    public void readFromParcel(Parcel in) {
        left = in.readInt();
        top = in.readInt();
        right = in.readInt();
        bottom = in.readInt();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @NonNull
    @Override
    public String toString() {
        return "Rect[left:" + left + ",top:" + top + ",right:" + right + ",bottom:" + bottom + "]";
    }
}

这样我们就可以在之前创建的 IRemoteService.aidl 中新增一个方法来传递 Rect 对象了,示例代码如下:

// IRemoteService.aidl
package com.example.aidl.server;
import com.example.aidl.server.Rect;

// Declare any non-default types here with import statements

interface IRemoteService {
    /**
     * 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);

    int getPid();

    void addRectInOut(inout Rect rect);
}

注意这里需要明确导包:

import com.example.aidl.server.Rect;

然后将新增的 Rect.aidl 文件和 Rect.java 文件还有修改的 IRemoteService.aidl 文件同步到客户端相同路径下,如图所示:
[Android AIDL] --- AIDL原理简析,Android,android
build 下工程,就可以在客户端调用到该 addRectInOut 方法了。示例代码如下:文章来源地址https://www.toymoban.com/news/detail-683619.html

    ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iRemoteService = IRemoteService.Stub.asInterface(service);
            try {
                iRemoteService.addRectInOut(new Rect(1, 2, 3, 4));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };

到了这里,关于[Android AIDL] --- AIDL原理简析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android studio 无法创建AIDL文件

    Android studio 创建AIDL文件的时候 提示是灰色的无法创建 处理方法在app下面的build.gradle中的buildFeatures 添加 aidl = true 这个是 kotlin的写法,如果是使用的旧项目修改下格式就行

    2024年01月25日
    浏览(37)
  • Android 使用AIDL传输超大型文件

    最近在写车载Android的第5篇视频教程「AIDL的实践与封装」时,遇到一个有意思的问题,能不能通过AIDL传输超过 1M 以上的文件? 我们先不细究,为什么要用AIDL传递大文件,单纯从技术的角度考虑能不能实现。众所周知,AIDL是一种基于Binder实现的跨进程调用方案,Binder 对传输

    2024年02月10日
    浏览(50)
  • android aidl进程间通信封装通用实现

    接上一篇的分析,今天继续 aidl复杂流程封装-CSDN博客 今天的任务就是将代码梳理下放进来 1 项目gradle配置:    需要将对应的代码放到各自的目录下,这里仅贴下关键内容,细节可以下载代码慢慢看     sourceSets {         main {             manifest.srcFile \\\'src/main/AndroidManife

    2024年02月22日
    浏览(36)
  • Android Binder——APP中AIDL实现(十九)

            AIDL(Android Interface Definition Language)其实就是对 Binder 通信的一个封装,方便在开发中对 Binder 通信的使用,这里我们就从头开始来看一下 AIDL 通信的创建过程。         通过 Android Studio 的 File -New - AIDL 的方式就会生成对应包名的 aidl 文件。即 aidl 文件要与应用

    2024年04月28日
    浏览(27)
  • 深入解析Android AIDL:实现跨进程通信的利器

    Android Interface Definition Language (AIDL) 是一种Android系统中的跨进程通信机制。AIDL允许一个应用程序的组件与另一个应用程序的组件通信,并在两者之间传输数据。 AIDL的主要作用是帮助不同进程间共享数据和服务,让他们能够互相调用。例如,在开发一个多功能的音乐播放器时,

    2024年02月19日
    浏览(41)
  • Android:AIDL简单介绍+传递简单数据+传递复杂数据

    对于AIDL的学习,这些也只能说是我在学习中的理解,有理解不到位或者错的地方也欢迎指正。 AIDL的目的就是实现进程之间的通信, 尤其是在涉及多进程并发情况下的进程间通信 。可以将aidl理解为两个进程之间的桥梁,并制定规则,使其传输特定数据。 1.AIDL支持的数据类型

    2024年02月21日
    浏览(37)
  • android aidl进程间通信封装通用实现-用法说明

    接上一篇:android aidl进程间通信封装通用实现-CSDN博客 该aar包的使用还是比较方便的 一先看客户端 1 初始化 2 发送事件:  就是通过json的形式将参数包裹进来,另一端统一解析  唯一标志位:KEY_CLIENT_REQUEST_AUTHOR 是必须要加的,不然区分不出来是那个客户端 二再看服务端

    2024年02月20日
    浏览(33)
  • Android中AIDL的简单使用(Hello world)

    AIDL:Android Interface Definition Language(Android接口定义语言) 作用:跨进程通讯。如A应用调用B应用提供的接口 A应用创建aidl接口,并且创建一个Service来实现这个接口(在onBind方法里面return我们这个接口的实例)。 把A应用创建的aidl文件原封不动的搬至B应用中(注意包名类名都

    2024年02月11日
    浏览(48)
  • Android FFmpeg应用简析

    FFmpeg是一个跨平台的自由软件,可用于录制、转换和流式传输音频和视频。它包含了非常多的音频/视频编解码库、封装格式库以及工具库。它不仅支持各种常用的音视频格式,而且支持一些非常罕见的格式。 FFmpeg实际上是一个命令行工具,可以在终端窗口中使用。它可以在

    2024年02月13日
    浏览(37)
  • Android Binder常用案例使用分析,跨进程通信aidl

    service组件的binderService获取binder通信。 servicemanager.getService方法获取相关服务。 本质上都是IBinder通信。 客户端:使用intent,启动服务端的service,使用binderservice,在onServiceConnected回调方法中获取服务端的实际binder对象。使用aidl中的接口调用服务端的方法即可。 服务端:定义

    2024年02月07日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包