Android kotlin语言AIDL使用

AIDL作为Android的一个IPC工具,可以用于进程间通信,进程间通信不仅是不同应用间也可以是同一个应用的不同进程间。Java语言使用AIDL的文档网上有太多,这里不以Java为例,使用Kotlin为例进行讲解。

前言

AIDL英文全写为(Android Interface Definition Language)直译为android接口定义语言。就是用来定义不同进程间通信所用的接口的语言。说白了就是一个帮助我们简化Binder开发的工具,我们按照AIDL的语法进行编写之后进行build操作时SDK中的AIDL.exe会自动为我们在build.generated.source.aidl文件夹中的debug或者release文件夹中生成对应名称的java文件,这个java文件实际使用了Binder机制。此篇文章浅显的讲述Kotlin语言使用AIDL进行进程间通信,至于这个java文件如何编写,我会在下一篇文章中进行讲述。在此感谢**[Android 开发艺术探索]**的作者任玉刚老师对知识的分享。

步骤

  1. 定义数据实体类
  2. 创建aidl文件
  3. make project(build),更改生成的java文件
  4. 创建服务端服务
  5. 创建客户端服务

在进行讲述之前我们先看一张最后完成的服务端的整体结构

Person.aidl文件是实体类对应的aidl文件,IMyAidl.aidl文件是生成Java文件的依据文件,Person.kt文件是定义的实体类,MyAidlService.kt文件是服务端服务文件

一、定义数据实体类

Person.kt

package com.example.com.testapplication.bean.kotlinimport android.annotation.SuppressLintimport android.os.Parcelableimport kotlinx.android.parcel.Parcelize@Parcelize@SuppressLint("ParcelCreator")class Person(var name: String) : Parcelable {override fun toString(): String {    return " [Person name = " + name + " ]"}}

随便定义了一个实体类使用注解实现了Parcelable

二、创建aidl文件

在main文件夹下创建aidl文件夹,在其中添加跟项目路径一致的文件夹并在其对应文件夹中创建aidl文件

Person.aidl

// Person.aidlpackage com.example.com.testapplication.bean.kotlin;// Declare any non-default types here with import statementsparcelable Person;

IMyAidl.aidl

// IMyAidl.aidlpackage com.example.com.testapplication;import com.example.com.testapplication.bean.kotlin.Person;// Declare any non-default types here with import statementsinterface IMyAidl {/** * 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出) *//** * 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 addPerson(in Person person);List getPersonList();}

三、make project(build),更改生成的java文件

在编写完aidl文件之后执行make project或者build之后会提示如下错误

虽然会出现上面的问题,但是需要的Java文件其实已经生成了。

这个错误的产生是因为kotlin的parcelable的实现CREATOR.createFromParcel会将返回类型当成any类型而不是指定类型,主要是因为kotlin的注解序列化机制产生的问题,如果你不是使用的@Parcelize注解进行的序列化那么就不会遇到这个问题,但是会遇到错误: CREATOR可以在Person中访问private,是因为Java与kotlin语言在机制上的冲突引起的。

解决上面的冲突方法也很简单,在本例中就是在生成的Java文件中使用Person.CREATOR.createFromParcel的地方加个强转

(Person) Person.CREATOR.createFromParcel(data)

四、创建服务端服务

在我们改完生成的Java文件后我们需要删除使用的aidl文件并将生成的文件放入对应的文件夹中而不是继续放在build中,因为在我们打包或者运行的时候每次都会检测aidl文件夹并且生成对应的文件,那么步骤三出现的问题就会一直出现。

上面的步骤做完之后我们就可以编写服务端具体逻辑代码了

MyAidlService.kt

package com.example.com.testapplication.serviceimport android.app.Serviceimport android.content.Intentimport android.os.IBinderimport com.example.com.testapplication.IMyAidlimport com.example.com.testapplication.bean.kotlin.Personclass MyAidlService : Service() {val mPersons by lazy { mutableListOf() }override fun onBind(intent: Intent?): IBinder = mIBinderprivate val mIBinder = object : IMyAidl.Stub() {    override fun addPerson(person: Person?) {        mPersons.add(person!!)    }    override fun getPersonList(): MutableList {        return mPersons    }}}

之后需要在AndroidManifest.xml文件中注册服务。

                                             

至此,服务端的我们就完成了。

五、创建客户端服务

我们假设使用aidl的是为了实现不同应用间的信息传递,那么我们就需要在新创建一个应用,并在这个应用中对应的放入需要的文件。

那么我们都需要什么呢?我们需要同路径下的数据实体类、已经改完的生成Java文件。在此不建议直接导入aidl文件夹,因为还需要重新更改生成的文件还项目增加结构复杂度。

将我们需要的文件都导入之后我们就可以使用bind绑定我们在服务端的服务进行跨进程开发了

另一个程序的MainActivity.kt

package com.aidl.zhang.aidltestapplicationimport android.content.ComponentNameimport android.content.Contextimport android.content.Intentimport android.content.ServiceConnectionimport android.os.Bundleimport android.os.IBinderimport android.support.v7.app.AppCompatActivityimport com.example.com.testapplication.IMyAidlimport com.example.com.testapplication.bean.kotlin.Personimport kotlinx.android.synthetic.main.activity_main.*import java.util.*class MainActivity : AppCompatActivity() {private var mAidl: IMyAidl? = nulloverride fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_main)    initAidlService()    btn_click.setOnClickListener {        mAidl?.addPerson(Person("测试" + Random().nextInt(5)))        val personList = mAidl?.personList        tv_aidl.setText(personList.toString())    }}private fun initAidlService() {    val intent = Intent()    intent.action = "testapplication.service.MyAidlService"    intent.`package` = "com.example.com.testapplication"    bindService(intent, MyServiceConnection(), Context.BIND_AUTO_CREATE)}inner private class MyServiceConnection : ServiceConnection {    override fun onServiceDisconnected(name: ComponentName?) {        mAidl = null    }    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {        mAidl = IMyAidl.Stub.asInterface(service)    }}}

至此我们的客户端也开发完了。整体流程走下李,我们知道kotlin语言的aidl开发比java语言的aidl开发多了一个更改生成文件的步骤,其他的都是一样的,而且就代码量来说个人觉得kotlin是真棒。

坑:

  1. aidl的编写上很容易遇到问题,要注意引入的类路径和类名
  2. aidl是基于binder内核进行的,也是CS结构的,如果服务端没有启动那么就像网络访问没有启动服务器一样是没有办法进行通信的。

致敬源码

更多相关文章

  1. SeekBar自定义样式最优实现
  2. Android系统编译系统分析大全(一)
  3. Android(安卓)的相关文件类型
  4. Android截屏浅析
  5. Android(安卓)动态logo bootanimation.zip 制作
  6. 如何给你的Android(安卓)安装文件(APK)瘦身
  7. Android中attrs.xml文件的使用详解
  8. 安卓selector使用方法
  9. Android(安卓)android下的数据持久化和读取数据,保存数据到手机及

随机推荐

  1. 一个关于android中ListView的子控件中按
  2. Android Thread Looper Handler 关系
  3. Android TextView 中文本横向滚动效果实
  4. Android中使用AlarmManager需注意设置进
  5. android Uri的常用几个例子
  6. Android Studio MQTT功能
  7. android 6.0 权限问题的解决
  8. android实现界面底部的tab
  9. android usb流程(加整理)
  10. TableLayout 属性的设置