IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> AIDL基本使用 -> 正文阅读

[移动开发]AIDL基本使用

一、大致流程

1.服务端创建 .aidl 文件
2.定义接口
3.build生成相应的java文件
4.向客户端公开接口(写一个service,重写onBind(),返回Stub类的实现)
5.复制aidl文件及相应的bean类(如果有的话)到客户端
6.客户端binderService拿到binder实例调用服务端方法。

例子:
1.服务端在src/main下创建aidl文件IPersonManager.aidl

// IPersonManager.aidl
package com.lmy.androidutilcode;

import com.lmy.androidutilcode.bean.Person;

interface IPersonManager {
    List<Person> getPersonList();
    boolean addPerson(inout Person person);
}

2.定义好要传输的对象Person

class Person(var name: String? = "") : Parcelable {
    constructor(parcel: Parcel) : this(parcel.readString())

    override fun toString(): String {
        return "Person(name=$name) hashcode = ${hashCode()}"
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
    }

    fun readFromParcel(parcel: Parcel) {
        this.name = parcel.readString()
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Person> {
        override fun createFromParcel(parcel: Parcel): Person {
            return Person(parcel)
        }

        override fun newArray(size: Int): Array<Person?> {
            return arrayOfNulls(size)
        }
    }

3.然后得在aidl的相同目录下也需要声明一下这个Person对象.新建一个Person.aidl

package com.xfhy.allinone.ipc.aidl;

parcelable Person;

如图:

在这里插入图片描述
4.rebuild一下,AS会自动生成如下代码IPersonManager.java。
在这里插入图片描述
注意:aidl文件中最好不要用中文注释

5.服务端像客户端公开接口
定义一个Service,然后将其process设置成一个新的进程,与主进程区分开(或者像我这里用2个module,即2个application)。模拟跨进程访问,它里面需要实现.aidl生成的接口

class RemoteService : Service() {

    private val mPersonList = mutableListOf<Person?>()

    private val mBinder: Binder = object : IPersonManager.Stub() {
        override fun getPersonList(): MutableList<Person?> = mPersonList

        override fun addPerson(person: Person?): Boolean {
            return mPersonList.add(person)
        }
    }

    override fun onBind(intent: Intent?): IBinder? {
        return mBinder
    }

    override fun onCreate() {
        super.onCreate()
        mPersonList.add(Person("Garen"))
        mPersonList.add(Person("Darius"))
    }
}

实现的IPersonManager.Stub是一个Binder,需要通过onBind()返回,客户端需要通过这个Binder来跨进程调用Service这边的服务.

6.复制aidl文件和相应的bean对象到客户端
注意:目录结构要完全一样
在这里插入图片描述

7.客户端调用

class AidlActivity : TitleBarActivity() {

    companion object {
        const val TAG = "lmy"
    }

    private var remoteServer: IPersonManager? = null

    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            log(TAG, "onServiceConnected")
            //在onServiceConnected调用IPersonManager.Stub.asInterface获取接口类型的实例
            //通过这个实例调用服务端的服务
            remoteServer = IPersonManager.Stub.asInterface(service)
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            log(TAG, "onServiceDisconnected")
        }
    }

    override fun getThisTitle(): CharSequence {
        return "AIDL"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_aidl)

        btnConnect.setOnClickListener {
            connectService()
        }
        btnGetPerson.setOnClickListener {
            getPerson()
        }
        btnAddPerson.setOnClickListener {
            addPerson()
        }
    }

    private fun connectService() {
        val intent = Intent()
        //action 和 package(app的包名)
        intent.action = "可以给服务端的service定义一个action"
        intent.setPackage("服务端包名")
        val bindServiceResult = bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
    }

    private fun addPerson() {
        //客户端调服务端方法时,需要捕获以下几个异常:
        //RemoteException 异常:
        //DeadObjectException 异常:连接中断时会抛出异常;
        //SecurityException 异常:客户端和服务端中定义的 AIDL 发生冲突时会抛出异常;
        try {
            val addPersonResult = remoteServer?.addPerson(Person("盖伦"))
            log(TAG, "addPerson result = $addPersonResult")
        } catch (e: RemoteException) {
            e.printStackTrace()
        } catch (e: DeadObjectException) {
            e.printStackTrace()
        } catch (e: SecurityException) {
            e.printStackTrace()
        }
    }

    private fun getPerson() {
        val personList = remoteServer?.personList
        log(TAG, "person 列表 $personList")
    }

    override fun onDestroy() {
        super.onDestroy()
        //最后记得unbindService
        unbindService(serviceConnection)
    }
}

注意:
如果targetSdk是30,那么需要处理Android 11中的程序包可见性 具体参见: https://developer.android.com/about/versions/11/privacy/package-visibility

二、in,out,inout关键字

在上面定义AIDL接口的时候,咱用到了一个关键字in,这个关键是其实是定向tag,是用来指出数据流通的方式。还有2个tag是out和inout,所有的非基本参数都需要一个定向tag来指出数据的流向,基本参数的定向tag默认并且只能是in。

in方式是可以从客户端向服务端传数据的,out则不行
out方式是可以从服务端向客户端传数据的,in则不行
不管服务端是否有修改传过去的对象数据,客户端的对象引用是不会变的,变化的只是客户端的数据,合情合理,跨进程是序列化与反序列化的方式操作数据。

三、oneway 关键字

将aidl接口的方法前加上oneway关键字则这个方法是异步调用,不会阻塞调用线程,当客户端这边调用服务端的方法时,如果不需要知道其返回结果,这时使用异步调用可以提高客户端的执行效率。

验证:我将aidl接口方法定义成oneway的,在服务端AIDL方法实现中加入Thread.sleep(2000)阻塞一下方法调用,然后客户端调用这个方法,查看方法调用的前后时间

private fun addPersonOneway() {
log(TAG, “oneway开始时间: ${System.currentTimeMillis()}”)
remoteServer?.addPersonOneway(Person(“oneway”))
log(TAG, “oneway结束时间: ${System.currentTimeMillis()}”)
}

//日志输出
//oneway开始时间: 1608858291371
//oneway结束时间: 1608858291372
可以看到,客户端调用这个方法时确实是没有被阻塞的.

四、线程安全

AIDL的方法是在服务端的Binder线程池中执行的,所以多个客户端同时进行连接且操作数据时可能存在多个线程同时访问的情形.这样的话,我们就需要在服务端AIDL方法中处理多线程同步问题.

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:57:45  更:2022-07-03 10:59:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 2:24:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码