一、App应用层AIDL使用
1.创建aidl文件:
使用AS开发在src/main/下创建AIDL;如果有需要传递自定义的类型,需要先进行序列化,再使用aidl声明一下;
// IMyAidl.aidl
package com.hxy.aidldemo;
import com.hxy.aidldemo.Book;
interface IMyAidl {
//简单定义一个获取书籍信息的方法
Book getBookMsg(String bookName);
}
2.进行编译:
rebuild project,目的是使用创建好的AIDL模板生成中间代码,便于后面实现使用,编译出的中间文件位于build/generated/aidl_source_output_dir/下,
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.hxy.aidldemo;
public interface IMyAidl extends android.os.IInterface
{
/** Default implementation for IMyAidl. */
public static class Default implements com.hxy.aidldemo.IMyAidl
{
//简单定义一个获取书籍信息的方法
@Override public com.hxy.aidldemo.Book getBookMsg(java.lang.String bookName) throws android.os.RemoteException
{
return null;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.hxy.aidldemo.IMyAidl
{
private static final java.lang.String DESCRIPTOR = "com.hxy.aidldemo.IMyAidl";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.hxy.aidldemo.IMyAidl interface,
* generating a proxy if needed.
*/
public static com.hxy.aidldemo.IMyAidl asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.hxy.aidldemo.IMyAidl))) {
return ((com.hxy.aidldemo.IMyAidl)iin);
}
return new com.hxy.aidldemo.IMyAidl.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookMsg:
{
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
com.hxy.aidldemo.Book _result = this.getBookMsg(_arg0);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.hxy.aidldemo.IMyAidl
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
//简单定义一个获取书籍信息的方法
@Override public com.hxy.aidldemo.Book getBookMsg(java.lang.String bookName) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
com.hxy.aidldemo.Book _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(bookName);
boolean _status = mRemote.transact(Stub.TRANSACTION_getBookMsg, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getBookMsg(bookName);
}
_reply.readException();
if ((0!=_reply.readInt())) {
_result = com.hxy.aidldemo.Book.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.hxy.aidldemo.IMyAidl sDefaultImpl;
}
static final int TRANSACTION_getBookMsg = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(com.hxy.aidldemo.IMyAidl impl) {
// Only one user of this interface can use this function
// at a time. This is a heuristic to detect if two different
// users in the same process use this function.
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.hxy.aidldemo.IMyAidl getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
//简单定义一个获取书籍信息的方法
public com.hxy.aidldemo.Book getBookMsg(java.lang.String bookName) throws android.os.RemoteException;
}
3.编写服务端
一般app中实现的话,都是在service中;实现中间类的.Stub()类,从上面的文件中也可看出Stub()是一个abstract类,需要有具体实现;
package com.hxy.aidldemo
import android.app.Service
import android.content.Intent
import android.os.IBinder
class MyService : Service() {
override fun onBind(intent: Intent): IBinder {
return mBinder
}
private val mBinder: IBinder = object : IMyAidl.Stub() {
override fun getBookMsg(bookName: String?): Book {
//调用Service实现中的具体方法,这里就简单的返回一个Book实例
return Book("架构师成长之路", 66.6, "本书详细描述了如何成为一个高手高高手")
}
}
}
4.客户端调用
客户端需要有server端的aidl接口文件,server端可以直接拷贝给client侧使用,client侧不要做任何修改;为了保证不出差错,建议将server端的aidl接口封装为一个jar包给到第三方使用;本例中为简便就在一个app里实现了,为了保证确实是跨进程了,service让其跑在了remote进程;
app中客户端调用的话一般可进行绑定服务操作,
package com.hxy.aidldemo
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.Toast
class MainActivity : AppCompatActivity() {
val tag: String = "MainActivity"
var mProxy: IMyAidl? = null
val connection = object: ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d(tag, "绑定服务")
mProxy = IMyAidl.Stub.asInterface(service)
Toast.makeText(this@MainActivity, "Server 绑定成功!", Toast.LENGTH_LONG).show()
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(tag, "服务断开")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btConnect = findViewById(R.id.bt_connect)
btConnect.setOnClickListener {
//启动绑定server端,运行在remote进程
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
btGetMsg = findViewById(R.id.bt_getmsg)
btGetMsg.setOnClickListener {
testFun()
}
}
override fun onResume() {
super.onResume()
// //启动server端,运行在remote进程
// val intent = Intent(this, MyService::class.java)
// this.startService(intent)
}
//作为客户端,定义一个按钮来调用
fun testFun() {
Log.d(tag, "调用远端server")
val book = mProxy?.getBookMsg("无用参数")
Log.d(tag, "书籍信息:${book.toString()}")
Toast.makeText(this@MainActivity, "Server 调用获取书籍信息:${book.toString()}", Toast.LENGTH_LONG).show()
}
lateinit var btConnect: Button
lateinit var btGetMsg: Button
}
源码示例:aidldemo
整体类图大致如下: