AIDL
开发过程中,当我们需要需要和其他进程交互的情况时,就不得不使用到AIDL
。
在AIDL
中我们可以使用基础类型数据、String 、CharSequence、List或Map(注意List和Map 对象的元素必须是AIDL支持的数据类)以及自己定义并申明的数据类型(此数据需要实现parcelable)。
这里以自己定义的数据类型进行说明。
服务端实现
首先我们创建一个项目作为服务端(提供AIDL实现的项目)。
创建AIDL文件
- 定义对应的需要在
AIDL
中使用的数据。
package com.duode.myjobinterview.aidl
import android.os.Parcel
import android.os.Parcelable
/**
* @author duode
* @des
* @date 2020/7/15 10:53
* */
data class AIDLData(var name: String, var flag: Int) : Parcelable {
constructor(source: Parcel) : this(
source.readString() ?: "",
source.readInt()
)
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
writeString(name)
writeInt(flag)
}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<AIDLData> = object : Parcelable.Creator<AIDLData> {
override fun createFromParcel(source: Parcel): AIDLData =
AIDLData(source)
override fun newArray(size: Int): Array<AIDLData?> = arrayOfNulls(size)
}
}
}
- 创建对应的
AIDL
文件申明此数据
// AIDLData.aidl
package com.duode.myjobinterview;
//申明需要在AIDL文件中使用的非常用类型;此文件的包名和数据类型的包名一定要一致
parcelable AIDLData;
可以使用
AndroidStudio
快速创建对应的AIDL
文件。
- 创建需要提供给外部调用的
AIDL
文件
// IDataInteractionAidlInterface.aidl
package com.duode.myjobinterview.aidl;
// 对非基础类型的数据需要进行导包;且注意此文件的包名和数据类型的包名一定要一致
import com.duode.myjobinterview.aidl.AIDLData;
interface IDataInteractionAidlInterface {
void setData(in AIDLData data);
AIDLData getData();
}
注意
:做完这些需要构建一下项目,以生产对应的AIDL服务
实现对应的远程服务
- 创建一个Service实现AIDL的具体调用
package com.duode.myjobinterview.servicer
import android.app.Service
import android.content.Intent
import android.os.IBinder
import com.duode.myjobinterview.aidl.AIDLData
import com.duode.myjobinterview.aidl.IDataInteractionAidlInterface
/**
* @author duode
* @des
* @date 2020/7/15 11:01
* */
class AIDLService : Service() {
private var mData: AIDLData? = null
val mIBinder = object : IDataInteractionAidlInterface.Stub() {
override fun getData(): AIDLData {
return mData ?: AIDLData("AIDLService", -1)
}
override fun setData(data: AIDLData?) {
mData = data
}
}
override fun onBind(p0: Intent?): IBinder? {
return mIBinder
}
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}
}
- 申明远程服务
<!--申明aidl服务,设置可以被外部调用,设置单独使用独立的进程-->
<service
android:name=".servicer.AIDLService"
android:exported="true"
android:process=":remote">
<intent-filter>
<!--申明可以被外部调用的action-->
<action android:name="com.duode.myjobinterview.servicer.AIDLService" />
</intent-filter>
</service>
客户端实现
创建需要调用远程服务的项目。
复制对应的AIDL数据到指定位置
这里的包名需要保持一致
复制对应的AIDL文件到指定位置
这里的包名需要保持一致
注意
:完成以上操作之后,需要进行编译项目以生成对应的文件。
实现服务绑定
package com.duode.client
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.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.duode.myjobinterview.aidl.AIDLData
import com.duode.myjobinterview.aidl.IDataInteractionAidlInterface
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
companion object {
val AIDL_ACTION = "com.duode.myjobinterview.servicer.AIDLService"
val AIDL_PKG = "com.duode.myjobinterview"
}
private var mAIDLInterface: IDataInteractionAidlInterface? = null
private val mServiceConnection = object : ServiceConnection {
override fun onServiceDisconnected(p0: ComponentName?) {//服务被异常销毁时回调,如内存不足
btn.text = "Connect"
}
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
btn.text = "Disconnected"
mAIDLInterface = IDataInteractionAidlInterface.Stub.asInterface(p1)
val data = mAIDLInterface?.data
Log.d("Servicer", "$data")
mAIDLInterface?.setData(AIDLData("Client", 1))
Log.d("Client", "${mAIDLInterface?.data}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn.setOnClickListener {
if (btn.text == "Connect") {
val intent = Intent()
intent.setPackage(AIDL_PKG)
intent.action = AIDL_ACTION
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)
} else {
unbindService(mServiceConnection)
btn.text = "Connect"
}
}
}
override fun onDestroy() {
unbindService(mServiceConnection)
super.onDestroy()
}
}