android kotlin aidl 通讯实现inout类型及回调监听

1.基本介绍

AIDl是Android中专门针对跨进程而设计的一种机制。AIDL全称是Android Interface Definition Language(安卓接口定义语言),使用它的语法和Java的风格很相似,主要用来不同应用和进程之间的通讯.(先上张图片)

先上个基本界面

2.相关知识介绍

1.AIDL支持的数据类型分为如下几种:

八种基本数据类型:byte、char、short、int、long、float、double、boolean
String,CharSequence
实现了Parcelable接口的数据类型
List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
Map类型和list一样

2**.定向Tag,分为in、out、inout 三种,所有的非基本参数都需要一个定向tag来指出数据流通的方式,不管是 in , out , 还是 inout ,基本参数的定向tag默认是并且只能是 in;** AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。其中,数据流向是针对在客户端中的那个传入方法的对象而言的。in 为定向 tag 的话表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动;out 的话表现为服务端将会接收到那个对象的的空对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动;inout 为定向 tag 的情况下,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。(详细信息看demo)

##3.创建服务端代码在服务端创建图书储藏室
在这里插入图片描述

1.服务端建立

先建立aidl接口,直接模块下创建aidl如图
在这里插入图片描述
基类aidl Book.aidl ,如图

package com.tt.server;
parcelable Book;

在对应的java目录添加Book对象实现Parcelable序列化 可以自动生成有部分需要手动添加

package com.tt.server

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

/**
 *   Created by chenmy on 2020/5/22.
 */
class Book() : Parcelable {
    var name: String = ""
    //添加构造函数
    constructor(name: String) : this() {
        this.name = name
    }
    
    constructor(parcel: Parcel) : this() {
        name = parcel.readString().toString()
    }

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

    override fun describeContents(): Int {
        return 0
    }
	//注意手动输入要不然很可能
    fun readFromParcel(dest: Parcel) {
        name = dest.readString().toString()
    }


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

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

作为回调的接口BookCallBack.aidl,主要获取服务端相关信息回调给客户端

// BookCallBack.aidl
package com.tt.server;
interface BookCallBack {
    void getCount(int count);
    void get4BookName(String bookName);
    void get3BookName(String bookName);
}

IBookService.aidl,定义相关实现接口,服务会实现相关接口逻辑

// IBookService.aidl
package com.tt.server;
// Declare any non-default types here with import statements
import com.tt.server.Book;
import com.tt.server.BookCallBack;

interface IBookService {

    List<Book> getaaBookList();

    void addInBook(in Book book);

    void addOutBook(out Book book);

    void addInOutBook(inout Book book);

    void get4BookName();

    void get3BookName();

    void registerCallback(BookCallBack bc);

    void unregisterCallback(BookCallBack bc);
}

创建BookAidlService为服务端,注册服务:

<service
          android:name=".BookService"
          android:enabled="true"
          android:exported="true">
          <intent-filter>
              <action android:name="com.tt.server.BookService" />
          </intent-filter>
</service>

BookAidlService代码创建对应的

package com.tt.server

import android.app.Service
import android.content.Intent
import android.os.*
import android.util.Log
import java.util.*

class BookService : Service() {
    private var bookList = ArrayList<Book>()
    private var isCount = true

    override fun onCreate() {
        super.onCreate()
        Log.d("szjjyh", "aaaa")
        for (i in 1..5) {
            val book = Book("小兵传奇:$i")
            val add = bookList.add(book)
        }
    }

    override fun onBind(intent: Intent): IBinder {
        Log.d("szjjyh", "onBind")
        return iBinder
    }

    override fun onDestroy() {
        Log.d("szjjyh", "onDestroy")
        super.onDestroy()
    }

    private val remoteCallbackList =
        RemoteCallbackList<BookCallBack>()
    private val iBinder = object : IBookService.Stub() {
        override fun addInBook(book: Book) {
            Log.d("szjjyh", "addInBook")
            book.name = "${book.name}- 服务端改名 in"
            bookList.add(book)
            Log.d("szjjyh", "addInBook 1")
        }

        override fun addOutBook(book: Book) {
            Log.d("szjjyh", "addOutBook")
            book.name = "${book.name}- 服务端改名 out"
            bookList.add(book)
            Log.d("szjjyh", "addOutBook 1")
        }

        override fun addInOutBook(book: Book) {
            Log.d("szjjyh", "addInOutBook")
            book.name = "${book.name}- 服务端改名 inout"
            bookList.add(book)
            Log.d("szjjyh", "addInOutBook 1")
        }
		
		//不能直接用getBookList()相当于booklist坑注意
        override fun getaaBookList(): MutableList<Book> {
            Log.d("szjjyh", "getBookList")
            return bookList
        }


        override fun get4BookName() {
            Log.d("szjjyh", "get4BookName")
            query4Book()
        }

        override fun get3BookName() {
            Log.d("szjjyh", "get3BookName")
            query3Book()
        }

        override fun registerCallback(bc: BookCallBack?) {
            val register = remoteCallbackList.register(bc)
            if (isCount) {
                startCount()
            }
        }

        override fun unregisterCallback(bc: BookCallBack?) {
            remoteCallbackList.unregister(bc)
        }

    }

    private fun startCount() {
        isCount = false
        Thread(Runnable {
            try {
                for (i in 1..19) {
                    Thread.sleep(1000)
                    val message = Message()
                    message.what = i
                    timeHandler.sendMessage(message)
                }
                isCount = true
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }).start()
    }

    private val timeHandler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            Log.i(javaClass.simpleName, "发送消息:" + msg.what)
            callBack(msg.what)
            super.handleMessage(msg)
        }
    }

    private fun callBack(info: Int) {
        val N = remoteCallbackList.beginBroadcast()
        try {
            for (i in 0 until N) {
                remoteCallbackList.getBroadcastItem(i).getCount(info)
            }
        } catch (e: RemoteException) {
            e.printStackTrace()
            Log.e("szjjyh", "", e)
        }
        remoteCallbackList.finishBroadcast()
    }

    private fun query4Book() {
        val N: Int = remoteCallbackList.beginBroadcast()
        if (bookList.size >= 4) {
            for (i in 0..bookList.size) {
                if (i == 3) {
                    try {
                        for (j in 0 until N) {
                            remoteCallbackList.getBroadcastItem(j)
                                .get4BookName(bookList[i].name)
                        }
                    } catch (e: RemoteException) {
                        Log.e("szjjyh", "jjyh", e)
                    }
                }
            }
        } else {
            try {
                for (j in 0 until N) {
                    remoteCallbackList.getBroadcastItem(j).get4BookName("不存在该书")
                }
            } catch (e: RemoteException) {
                Log.e("szjjyh", "jjyh", e)
            }
        }
        remoteCallbackList.finishBroadcast()
    }

    private fun query3Book() {
        val N: Int = remoteCallbackList.beginBroadcast()
        if (bookList.size >= 3) {
            for (i in 0..bookList.size) {
                if (i == 2) {
                    try {
                        for (j in 0 until N) {
                            remoteCallbackList.getBroadcastItem(j)
                                .get3BookName(bookList[i].name)
                            bookList.removeAt(i)
                        }
                    } catch (e: RemoteException) {
                        Log.e("szjjyh", "jjyh", e)
                    }
                }
            }
        } else {
            try {
                for (j in 0 until N) {
                    remoteCallbackList.getBroadcastItem(j).get3BookName("书籍低于三本")
                }
            } catch (e: RemoteException) {
                Log.e("szjjyh", "jjyh", e)
            }
        }
        remoteCallbackList.finishBroadcast()
    }
}
2.客户端

需要将服务端对应的代码复制到客户端建红色框框
在这里插入图片描述
MainActivity代码

package com.tt.aidlclient
//...
class MainActivity : AppCompatActivity(), View.OnClickListener {
    private var isConnectService = false
    private var iBookService: IBookService? =null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        tv_3.movementMethod = ScrollingMovementMethod()
        bt_1.setOnClickListener(this)
        bt_2.setOnClickListener(this)
        bt_3.setOnClickListener(this)
        bt_4.setOnClickListener(this)
        bt_5.setOnClickListener(this)
        bt_6.setOnClickListener(this)
    }

    override fun onStart() {
        super.onStart()
        //连接服务
        connectService()
    }

//点击事件
    override fun onClick(v: View?) {
        if (!isConnectService) {
            connectService()
            Toast.makeText(
                this, "当前与服务端处于未连接状态,正在尝试重连," +
                        "请稍后再试", Toast.LENGTH_SHORT
            ).show()
            return
        }
        when (v!!.id) {
            R.id.bt_1 -> {
                val book1 = Book("客户端书 in")
                try {
                    iBookService?.addInBook(book1)
                    tv_1.text = "in由客户端流向服务端,客户端不能收到服务端具体信息,如下书名:${book1.name}"
                    getBookList(iBookService?.getaaBookList() as List<Book>)
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
            }
            R.id.bt_2 -> {
                val book2 = Book("客户端书 out")
                try {
                    iBookService?.addOutBook(book2)
                    tv_1.text = "out由服务端流向客户端,服务端不能收到客户端具体信息,如下书名:${book2.name}"
                    getBookList(iBookService?.getaaBookList() as List<Book>)
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
            }
            R.id.bt_3 -> {
                val book3 = Book("客户端书 inOut")
                try {
                    iBookService?.addInOutBook(book3)
                    tv_1.text = " inout客户端和服务端双向流通,如下书名:${book3.name}"
                    getBookList(iBookService?.getaaBookList() as List<Book>)
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
            }
            R.id.bt_4 -> try {
                iBookService?.registerCallback(bookCallBack)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
            R.id.bt_5 -> try {
                iBookService?.registerCallback(bookCallBack)
                iBookService?.get4BookName()
                getBookList(iBookService?.getaaBookList() as List<Book>)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
            R.id.bt_6 -> try {
                iBookService?.registerCallback(bookCallBack)
                iBookService?.get3BookName()
                getBookList(iBookService?.getaaBookList() as List<Book>)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
    }
    fun getBookList(bookList: List<Book>) {
        if (bookList.size > 0) {
            val buffer = StringBuffer()
            for (i in bookList.indices) {
                buffer.append("${i + 1}  号: ${bookList[i].name} \n")
            }
            tv_3.text = buffer
        }
    }

    //链接服务端
    private fun connectService() {
        Log.d("szjjyh", "jjyh connectService")
        val intent = Intent()
        intent.component =
            ComponentName("com.tt.server", "com.tt.server.BookService")

        intent.action = "com.tt.server.BookService"
//        intent.setPackage("com.tt.server")
        val bindService = bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
        Log.d("szjjyh", "jjyh connectService: "+bindService)
    }

//连接的监听
    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            Log.d("szjjyh", "jjyh 完成AIDLService服务")
            iBookService = IBookService.Stub.asInterface(service)
            isConnectService = true
        }

        override fun onServiceDisconnected(name: ComponentName) {
            Log.d("szjjyh", "jjyh 无法绑定aidlserver的AIDLService服务")
            isConnectService = false
            iBookService =null
        }
    }

    //实现回调接口获取相关数据
    private val bookCallBack = object : BookCallBack.Stub() {
        override fun get4BookName(bookName: String?) {
            tv_1.text = "获取到第4号书名:$bookName"
        }

        override fun get3BookName(bookName: String?) {
            tv_1.text = "获取到删除的第3号书名:$bookName"
        }

        override fun getCount(count: Int) {
            runOnUiThread { tv_2.text = "收到服务端数据:$count" }
        }

    }
}

在这里插入图片描述
点击in添加书籍
到此分析结束:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值