美文网首页Android
利用AIDL实现进程间通讯

利用AIDL实现进程间通讯

作者: 超人TIGA | 来源:发表于2020-12-22 10:58 被阅读0次

    这里只是简单地教大家如何初步认识,如何利用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

    相关文章

      网友评论

        本文标题:利用AIDL实现进程间通讯

        本文链接:https://www.haomeiwen.com/subject/kagjnktx.html