当前位置: 首页 > article >正文

Android在kts中简单使用AIDL

Android在kts中简单使用AIDL

AIDL相信做Android都有所了解,跨进程通信会经常使用,这里就不展开讲解原理跨进程通信的方式了,最近项目换成kts的方式,于是把aidl也换成了统一的方式,其中遇到了很多问题,这里记录一下,直接上代码.

1.在groovy创建aidl文件:

在Groovy中是可以直接创建aidl文件的

在这里插入图片描述

2.生成的aidl文件如下:

在这里插入图片描述

interface IMyService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    int add(int a, int b);
}

3.创建一个服务端Service:

MyService

package com.example.aidltestdemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import androidx.annotation.Nullable;


/**
 * @author: njb
 * @date: 2025/3/20 17:47
 * @desc: 描述
 */
public class MyService extends Service {
    private final IMyService.Stub mBinder = new IMyService.Stub() {


        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

4.注册服务:

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.aidltestdemo.IMyService" />
    </intent-filter>
</service>

在这里插入图片描述

5.客户端代码:

package com.example.aidltestdemo;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.google.android.material.snackbar.Snackbar;

public class MainActivity extends AppCompatActivity {

    private IMyService mService;
    private TextView textView;
    private static final  String TAG = "AIDlDemo";

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = IMyService.Stub.asInterface(service);
            try {
                int result = mService.add(10086, 10010);
                Log.d(TAG,"---获取到的数据为---: " + result);
                Snackbar.make(textView,"获取到的数据为: " + result,Snackbar.LENGTH_SHORT).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initService() {
        Intent intent = new Intent();
        intent.setAction("com.example.aidltestdemo.IMyService");
        intent.setPackage("com.example.aidltestdemo");
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    private void initView() {
        textView = findViewById(R.id.textView);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                initService();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }
}

6.布局文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="aidl简单测试"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

7.在kts中使用aidl:

如果是使用kts的方式默认创建aidl文件时提示没有配置创建不了,这就和之前有很大的区别。

在这里插入图片描述

8.在build.gradle添加配置:

在这里插入图片描述

再次创建aidl发现按钮是可以点击的,配置是有效果的。

在这里插入图片描述

9.新创建后的aidl文件:

在这里插入图片描述

9.1 服务端代码如下:

package com.example.aidldemo.server

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.RemoteException
import com.example.aidldemo.aidl.IMyTestServer

/**
 * @author: njb
 * @date: 2025/3/19 23:24
 * @desc: 描述
 */
class MyTestService : Service() {
    private val mBinder: IMyTestServer.Stub = object : IMyTestServer.Stub() {
        @Throws(RemoteException::class)
        override fun basicTypes(
            anInt: Int,
            aLong: Long,
            aBoolean: Boolean,
            aFloat: Float,
            aDouble: Double,
            aString: String
        ) {
        }

        @Throws(RemoteException::class)
        override fun add(a: Int, b: Int): Int {
            return a + b
        }
    }

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

9.2 注册服务:

<service android:name=".server.MyTestService"
    android:process=":remote"
    android:enabled="true"
    android:exported="true">

9.3 客户端代码:

package com.example.aidldemo.aidl

import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.aidldemo.R
import com.example.aidldemo.server.MyTestService
import com.google.android.material.snackbar.Snackbar


class MainActivity : AppCompatActivity(){
    private lateinit var mTvBind: TextView
    private val TAG = MainActivity::class.java.name
    private var testServer: IMyTestServer ?=null

    private val mConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            testServer = IMyTestServer.Stub.asInterface(service)
            try {
                testServer?.let {
                    val result: Int = it.add(188, 288)
                    Log.d(TAG, "--结果为--: $result")
                    Snackbar.make(mTvBind,"--获取到的数据为--: $result",Snackbar.LENGTH_SHORT).show()
                }

            } catch (rme: RemoteException) {
                rme.printStackTrace()
            }
        }

        override fun onServiceDisconnected(name: ComponentName) {
            try {
                testServer = null
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mTvBind = findViewById(R.id.tv_bind)
        mTvBind.setOnClickListener{
            val intent = Intent(
                this@MainActivity,
                MyTestService::class.java
            )
            bindService(intent, mConnection, BIND_AUTO_CREATE)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if(testServer != null && testServer!!.asBinder().isBinderAlive){
            testServer = null
        }
        unbindService(mConnection)
    }

}

10.新建一个Book服务:

// ICarManager.aidl
package com.example.aidldemo.aidl;
import com.example.aidldemo.aidl.Book;
import com.example.aidldemo.aidl.IOnNewBookAddListener;
// Declare any non-default types here with import statements

interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    List<Book> getBookList();
    void addNewBook(in Book book);
    void registerListener(IOnNewBookAddListener listener);
    void unregisterListener(IOnNewBookAddListener listener);
}

11.新增Book列表数据接口:

// IOnNewCarAddListener.aidl
package com.example.aidldemo.aidl;
import com.example.aidldemo.aidl.Book;
// Declare any non-default types here with import statements

interface IOnNewBookAddListener {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    void onNewBookAdd(in Book newBook);
}

12.IBook接口:

interface IBook {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

13.注册服务:

<service android:name=".server.BookManagerService"
    android:process=":remote"
    android:enabled="true"
    android:exported="true">
</service>

14.客户端Book测试代码:

package com.example.aidldemo.aidl

import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
import com.example.aidldemo.R
import com.example.aidldemo.databinding.ActivityMainBinding
import com.example.aidldemo.server.BookManagerService

/**
 * @author: njb
 * @date:   2025/3/22 19:27
 * @desc:   描述
 */
class BookTestActivity :AppCompatActivity(){
    private val TAG: String = "TestActivity"
    private var bookManager: IBookManager? = null
    private lateinit var binding:ActivityMainBinding
    private val mConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            bookManager = IBookManager.Stub.asInterface(service)
            try {
                bookManager?.let {
                    val books = it.getBookList()
                    if (books != null && books.isNotEmpty()) {
                        Log.d(TAG, " -- onServiceConnected -- book:$books")
                    }
                    it.registerListener(clientListener)
                }

            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }

        override fun onServiceDisconnected(name: ComponentName) {
            try {
                bookManager?.unregisterListener(clientListener)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
    }

    private val clientListener: IOnNewBookAddListener = object : IOnNewBookAddListener.Stub() {
        @Throws(RemoteException::class)
        override fun basicTypes(
            anInt: Int,
            aLong: Long,
            aBoolean: Boolean,
            aFloat: Float,
            aDouble: Double,
            aString: String
        ) {
        }

        @Throws(RemoteException::class)
        override fun onNewBookAdd(newBook: Book) {
            Log.d(TAG, " -- onNewBookAdd -- newBook:$newBook")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.tvBind.setOnClickListener{
            val intent = Intent(this@BookTestActivity, BookManagerService::class.java)
            bindService(intent, mConnection, BIND_AUTO_CREATE)
        }
        binding.tvGet.setOnClickListener{
            try {
                val books = bookManager!!.bookList
                if (books != null && books.isNotEmpty()) {
                    Log.d(TAG, " -- onClick -- books:$books")
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        binding.tvAdd.setOnClickListener{
            try {
                bookManager?.let {
                    it.addNewBook(Book(1003, "计算机组成原理"))
                    it.addNewBook(Book(1004, "操作系统"))
                }
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (bookManager != null && bookManager!!.asBinder().isBinderAlive) {
            try {
                bookManager?.unregisterListener(clientListener)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }

        unbindService(mConnection)
    }
}

15.普通实体类序列化:

package com.example.aidldemo.aidl;

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

import androidx.annotation.NonNull;

/**
 * @author: njb
 * @date: 2025/3/19 23:22
 * @desc: 描述
 */
public class Book implements Parcelable {

    private int id;
    private String name;

    public Book(int id, String name){
        this.id = id;
        this.name = name;
    }

    protected Book(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
    }

    @NonNull
    @Override
    public String toString() {
        return String.format("[id:%d, name:%s]",id, name);
    }

}

16.使用Parcelize序列化:

16.1 在app的build.gradle目录添加插件配置:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    id ("kotlin-parcelize")
}

在这里插入图片描述

16.2 实体类使用Parcelize方式:

和普通的方式对比发现代码简洁了很多,而且使用很方便,大大减少了开发人员的工作,当然我们要搞懂其原理才能达到事半功倍的效果,要不然只是会使用,而不知道为啥这么使用及使用他的优势和原理,对自身成长有限.

@Parcelize
data class Book(
    val id: Int,
    val name:String
):Parcelable

16.3 在libs.versions.toml添加如下插件:

jetbrains-kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }

16.4 在项目build.gradle添加配置:

plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.jetbrains.kotlin.android) apply false
    alias(libs.plugins.jetbrains.kotlin.parcelize) apply false
}

在这里插入图片描述

16.5 在app的build.gradle配置:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    alias(libs.plugins.jetbrains.kotlin.parcelize)
}

在这里插入图片描述

17.Parcelable的优势如下:

  • 高效性能:相比Serializable,Parcelable在序列化和反序列化过程中更加高效,因为它避免了反射的开销。
  • 跨进程传输:Parcelable适用于在不同进程之间传输数据,例如在Android中,我们可以将Parcelable对象传递给另一个应用程序组件。
  • 灵活性:Parcelable允许我们选择性地序列化对象的某些字段,而不是整个对象,这在某些情况下可以提高性能和减少传输的数据量。

18.遇到问题如下:

18.1 项目编译失败:

创建的Book服务和Book实例不在一个目录导致编译失败

在这里插入图片描述

在这里插入图片描述

18.2 把两个类放同一目录编译成功:

在这里插入图片描述

18.3 添加Parcelize插件依赖报错:

在这里插入图片描述

18.4 在build.gradle.kts添加以下配置:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    id ("kotlin-parcelize")
}

18.5 使用Version Catalog方式:

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
jetbrains-kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.jetbrains.kotlin.android) apply false
    alias(libs.plugins.jetbrains.kotlin.parcelize) apply false
}
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    alias(libs.plugins.jetbrains.kotlin.parcelize)
}

19.实现的效果如下:

在这里插入图片描述

在这里插入图片描述

20.日志打印如下:

o                 D  Installing profile for com.example.aidldemo
2025-03-23 20:26:39.912  4722-4722  TestActivity            com.example.aidldemo                 D   -- onServiceConnected -- book:[Book(id=1001, name=Java入门到精通)]
---------------------------- PROCESS STARTED (4797) for package com.example.aidldemo ----------------------------
2025-03-23 20:26:42.911  4722-4741  TestActivity            com.example.aidldemo                 D   -- onNewBookAdd -- newBook:Book(id=1002, name=C++程序设计)
2025-03-23 20:27:24.033  4722-4722  TestActivity            com.example.aidldemo                 D   -- onClick -- books:[Book(id=1001, name=Java入门到精通), Book(id=1002, name=C++程序设计)]
2025-03-23 20:27:39.776  4722-4722  TestActivity            com.example.aidldemo                 D   -- onNewBookAdd -- newBook:Book(id=1003, name=计算机组成原理)
2025-03-23 20:27:39.777  4722-4722  TestActivity            com.example.aidldemo                 D   -- onNewBookAdd -- newBook:Book(id=1004, name=操作系统)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

21.总结:

  • 使用kts的方式需要先使用buildFeatures配置aidl.
  • 使用Parcelize序列化数据很简单方便.
  • 要注意创建aidl文件的目录和包名这些在同一目录.
  • 使用Version Catalog方式要主要依赖配置的方式.
  • 感兴趣的小伙伴可以自己尝试一下,后面会讲解aidl如何传输大文件.

22.源码如下:

https://gitee.com/jackning_admin/aidl-test-demo


http://www.kler.cn/a/599121.html

相关文章:

  • Layotto 是一款使用 Golang 开发的应用运行时,旨在帮助开发人员快速构建云原生应用
  • Uniapp:基于 Vue.js 的高效跨平台开发框架
  • spring.datasource.filters = stat,wall配置解释
  • PostgreSQL 触发器
  • 耘想Docker版Linux NAS的安装说明
  • MAC+PHY 的硬件连接
  • 【重构小程序】基于Tika和Langchain4J进行文件解析和文本切片(二)
  • 使用DeepSeek翻译英文科技论文,以MarkDown格式输出,使用Writage 3.3.1插件转换为Word文件
  • Android使用RxHttp进行国密4加密解密
  • 【SpringBatch】05Item数据:读|处理|写|:Reader|Processor|Writer
  • git 仓库迁移 git clone --mirror git push --mirror
  • 从零构建大语言模型全栈开发指南:第一部分:数学与理论基础-1.2.1RNN与LSTM的局限性
  • Java Stream两种list判断字符串是否存在方案
  • yolo目标检测算法在DJI上的研究分析(大纲)
  • 【蓝桥杯速成】| 10.回溯切割
  • 2025年如何避免使用验证码求解器时被IP封禁
  • pta 乐子人游戏
  • 意法半导体 (ST) 推出的短距离无线 MCU STM32WBA6----可用于连接工业设备的
  • 练习用Jupyter使用selenium【疑问未解决版】
  • 机器臂运动控制算法工程师面试