利用AIDL实现进程间通讯

这里只是简单地教大家如何初步认识,如何利用AIDL来实现进程间通讯的代码编写,并非深入了解源码。

实现服务端

1、新建实体类,实现Parcelable接口
package com.tonydash.aidl.bean

import android.os.Parcel
import android.os.Parcelable

class Person() : Parcelable {

    var name: String = ""
    var age: Int = 0

    constructor(name: String, age: Int) : this() {
        this.name = name
        this.age = age
    }

    constructor(parcel: Parcel) : this() {
        name = parcel.readString().toString()
        age = parcel.readInt()
    }

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

    fun readFromParcel(dest: Parcel) {
        name = dest.readString().toString()
        age = dest.readInt()
    }

    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)
        }
    }
}

大部分都是自动生成的代码,如果有自己需要的构造函数或者方法需要增加,自行增加就好。
这里为什么一定要实现Parcelable接口?
因为binder默认支持的就是8大基础类型,如果要传自己的对象类型的数据,就要实现Parcelable,使得这个对象是可以被打包的数据,从而进行数据传递。

2、新建aidl文件

image.png
先在main文件夹下面新建一个aidl文件夹,然后在aidl文件夹中新建aidl文件,创建成功后就会自动帮你加上包路径,不需要自己建立。
这里需要注意的是,IPerson.aidl的包路径,是com.tonydash.aidl,所以对应下方java的路径,也只是com.tonydash.aidl,但是下方的Person类,却放在了bean文件夹中,这样默认的IPerson.aidl是找不到Person类的,所以我们需要改一下

//默认的包名是com.tonydash.aidl
//但是由于我的实体类Person,存放的位置我放在了com.tonydash.aidl.bean中
//所以这里也需要修改,不然无法关联到
package com.tonydash.aidl.bean;

//声明Person
parcelable Person;

interface IPersonAidlInterface {
    void addPersonIn(in Person person);
}
3、新建一个Service
package com.tonydash.aidl

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
import com.tonydash.aidl.bean.IPersonAidlInterface
import com.tonydash.aidl.bean.Person

class PersonService:Service() {

    private val personList = ArrayList<Person>();

    private val personBinder:IPersonAidlInterface.Stub =object : IPersonAidlInterface.Stub(){
        override fun addPersonIn(person: Person?) {
            Log.d("TAG","我是服务器,我收到一个客户端发过来的人:name = ${person?.name}")
        }

    }

    override fun onCreate() {
        super.onCreate()
        Log.d("PersonService","PersonService onCreate")
//        for (i in 1 .. 5){
//            personList.add(Person("name$i",i))
//        }
    }

    override fun onBind(intent: Intent?): IBinder {
        return personBinder
    }
}
4、MainActivity启动Service
package com.tonydash.aidl

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        startService(Intent(this,PersonService::class.java))
    }
}
5、注册service
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tonydash.aidl">

    <!--自定义权限,name 随便写,对应服务的权限就好-->
    <permission
        android:name="com.permission.aidl"
        android:protectionLevel="normal" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AIDL">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--
        exported = "true":可让其他 app 使用服务
        permission: 若 exported = "true",则需要给这个服务一个自定义的权限
        使用方若调用该服务就要声明这个权限,否则报错
        -->
        <service android:name=".PersonService"
            android:exported="true"
            android:permission="com.permission.aidl">
            <intent-filter>
                <!--定义action给客户端隐式调用,可随便写-->
                <action android:name="com.tiga.action.aidl" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>
    </application>

</manifest>

注册里会定义一个权限,是给其他APP调用时用的。到这里,服务端就完成了。

实现客户端

1、新建一个model或者project都可以
2、增加服务端定义的权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tonydash.client">

    <permission android:name="com.permission.aidl"/>
    <uses-permission android:name="com.permission.aidl"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AIDL">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
3、把服务端中的IPerson.aidl和Person类,连包路径一起都复制到client中。
image.png

一定要完全一致,不然会有问题

4、编写发送消息的逻辑
package com.tonydash.client

import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.tonydash.aidl.bean.IPersonAidlInterface
import com.tonydash.aidl.bean.Person


class MainActivity : AppCompatActivity() {

    var tvName:TextView? = null
    var iPerson:IPersonAidlInterface? = null

    val connection:ServiceConnection = object : ServiceConnection{
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            iPerson = IPersonAidlInterface.Stub.asInterface(service)
        }

        override fun onServiceDisconnected(name: ComponentName?) {

        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tvName = findViewById(R.id.tvName)
        tvName?.setOnClickListener {
            val person = Person()
            person.name = "奔波儿灞"
            person.age = 500
            iPerson?.addPersonIn(person)
        }
        connectService()
    }

    private fun connectService() {
        val intent = Intent()
        //服务端包名
        intent.setPackage("com.tonydash.aidl")
        //服务端设置的 action
        intent.action = "com.tiga.action.aidl"
        bindService(intent, connection, BIND_AUTO_CREATE)
    }
}
测试步骤

先把服务端APP启动起来,然后退到后台;
再把客户端APP启动起来,然后点击中间的TextView;

之后就可以在Logcat中看到消息了。
image.png

Demo地址:https://github.com/TonyDash/AIDL.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容