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

【Android AIDL之详细使用】

Android AIDL之详细使用

  • 一级目录
  • 概述
  • 使用场景
  • 语法相关
  • 编码实践
    • 服务端:
      • java文件
      • 修改AndroidManifest
    • 客户端

一级目录

概述

AIDL叫Android接口定义语言,是用于辅助开发者完成Android跨进程编程的工具。

从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此而生成的一个IInterface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板。

设计AIDL这门语言的目的就是为了实现进程间通信。在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求

通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的Service来进行交互

使用场景

  • App开发中,webview的优化是个绕不开的,而且与native的相互通信经常会碰到crash情况,webview写到一个单独的进程中,通过aidl通信,就很大程度上避免了这种情况;

  • 现在车机开发需求比较大,车机上的app相互通信的情况是比较多的,尤其是与语音的交互,只要需要让语音操作的App都是需要暴露接口给语音模块的;一般的暴露接口都是需要AIDL的方式来暴露;

语法相关

AIDL的语法十分简单,与Java语言基本保持一致,但是需要记住以下几点规则:

  • AIDL文件以 .aidl 为后缀名

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

    • 八种基本数据类型:byte、char、short、int、long、float、double、boolean
    • String,CharSequence
    • 实现了Parcelable接口的数据类型
    • List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
    • Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
    • 实现了Parcelable接口的数据类型
  • AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值

  • 定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。

  • 明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下

编码实践

纸上得来终觉浅,绝知此事要躬行,show your the code;客户端通过绑定服务端的Service的方式来调用服务端的方法,实现模拟登录,获取书籍详情的的功能,实现应用间的数据共享。

服务端:

java文件

先把 service 创建出来

public class AIDLService extends Service {@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}

新建一个工程,包名就定义为 com.ze.aidlservice
首先,在应用中需要用到一个 Book 类,而 Book 类是两个应用间都需要使用到的,所以也需要在AIDL文件中声明Book类,为了避免出现类名重复导致无法创建文件的错误,这里需要先建立 BookManager AIDL 文件,之后再创建 Book 类

右键点击app新建一个AIDL文件,命名为 IMyBookManager。
在这里插入图片描述
会自动在main目录下生成IMyBookManager aidl文件;
在这里插入图片描述
然后我们来定义Book类,包含两个属性,name和price;

public class Book implements Parcelable {private int price;private String name = "";public Book(){}protected Book(Parcel in) {price = in.readInt();name = in.readString();}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int describeContents() {return 0;}public static final Creator<Book> CREATOR = new Creator<Book>() {@Overridepublic Book createFromParcel(Parcel in) {return new Book(in);}@Overridepublic Book[] newArray(int size) {return new Book[size];}};@Overridepublic String toString() {return "\n图书名称:" + name + "\n图书价格:" + price;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(price);dest.writeString(name);}
}

然后修改IMyBookManager.aidl文件,增加了三个方法,和一个Book的声明,包括服务端需要暴露给客户端一个登录接口,和获取书籍详情,获取书籍价格的方法。

在这里插入图片描述
上面说过,在进程间通信中真正起作用的并不是 AIDL 文件,而是系统据此而生成的文件,可以在以下目录中查看系统生成的文件。之后需要使用到当中的内部静态抽象类 Stub

创建或修改过AIDL文件后需要重新makeproject下工程,使系统及时生成我们需要的文件;
在这里插入图片描述
现在修改 AIDLService供客户端远程绑定了。

public class AIDLService extends Service {MyBookManager bookManager = new MyBookManager();public AIDLService() {Log.d("jackie","service,AIDLService");}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d("jackie","service,onbind");return bookManager;}public class MyBookManager extends IMyBookManager.Stub{@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {}@Overridepublic String login(String userName, String pwd) throws RemoteException {Log.d("jackie","service,login");if(userName.equalsIgnoreCase("admin") && pwd.equalsIgnoreCase("123456")){return "success";}return "error";}@Overridepublic Book queryByName(String bookName) throws RemoteException {Log.d("jackie","service,queryByName");Book book = new Book();book.setName(bookName);book.setPrice(100);return book;}@Overridepublic String getBookPrice(String name) throws RemoteException {return name+" :30";}}
}

可以看到, onBind 方法返回的就是 IMyBookManager.Stub 对象,实现当中定义的三个方法。

修改AndroidManifest

客户端要能够找到这个Service,可以通过先指定包名,之后再配置Action值或者直接指定Service类名的方式来绑定Service
如果是通过指定Action值的方式来绑定Service,那还需要将Service的声明改为如下所示:

        <serviceandroid:name="com.ze.aidlservice.service.AIDLService"android:enabled="true"android:exported="true"android:process=":remote"><intent-filter><action android:name="com.ze.aidlservice.bookService"/><category android:name="android.intent.category.DEFAULT" /></intent-filter></service>
标签名含义
android:enabled该服务能否被实例化,默认为true
android:exported其他应用的组件能否和这个服务交互
导android:process设置独立进程,例如 remote 则进程名为 包名:remote

我们采用配置 Action 的方案。

还有个需要特别需要注意的点:从Android 11 开始 系统对app的可见性进行了保护,只有部分应用可见所有app。如果系统是11以上,需要在AndroidManifest里面声明

    <queries><package android:name="com.ze.aidlservice" /><intent><action android:name="com.ze.aidlservice.bookService" /></intent></queries>

客户端

创建新的工程,包名:com.ze.aidlclient;

首先,需要把服务端的AIDL文件以及Book类复制过来,将 aidl 文件夹整个复制到和Java文件夹同个层级下,不需要改动任何代码。
在这里插入图片描述
注意:Book类所在的包名要与服务的的包名相同。

布局文件:

<?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:layout_width="match_parent"android:layout_height="match_parent"tools:context=".FirstFragment"><Buttonandroid:id="@+id/btnConnection"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="140dp"android:layout_marginTop="52dp"android:text="连接服务测试"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"android:layout_marginLeft="140dp" /><TextViewandroid:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="56dp"android:layout_marginLeft="56dp"android:layout_marginTop="156dp"android:text="账户:"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/textView3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="4dp"android:layout_marginLeft="4dp"android:layout_marginTop="52dp"android:text="密码:"app:layout_constraintStart_toStartOf="@+id/textView2"app:layout_constraintTop_toBottomOf="@+id/textView2" /><EditTextandroid:id="@+id/etName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ems="10"android:hint="用户名"android:inputType="textPersonName"app:layout_constraintBottom_toBottomOf="@+id/textView2"app:layout_constraintStart_toEndOf="@+id/textView2"app:layout_constraintTop_toTopOf="@+id/textView2" /><EditTextandroid:id="@+id/etPwd"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ems="10"android:hint="密码"android:inputType="textPassword"app:layout_constraintBottom_toBottomOf="@+id/textView3"app:layout_constraintStart_toStartOf="@+id/etName"app:layout_constraintTop_toTopOf="@+id/textView3" /><Buttonandroid:id="@+id/btnLogin"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="160dp"android:layout_marginLeft="160dp"android:layout_marginTop="40dp"android:text="登录"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/textView3" /><TextViewandroid:id="@+id/tvBookInfo"android:scrollbarStyle="outsideInset"android:layout_width="303dp"android:layout_height="141dp"android:layout_marginTop="36dp"android:gravity="start|top"android:text="查询到的图书信息:"android:textSize="16dp"android:maxLines="5"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.555"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/etBookName" /><TextViewandroid:id="@+id/textView5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="60dp"android:text="书名:"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/btnLogin"android:layout_marginLeft="16dp" /><Buttonandroid:id="@+id/btnQuery"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:layout_marginLeft="20dp"android:text="查询"app:layout_constraintBottom_toBottomOf="@+id/textView5"app:layout_constraintStart_toEndOf="@+id/etBookName"app:layout_constraintTop_toTopOf="@+id/textView5"app:layout_constraintVertical_bias="0.517" /><EditTextandroid:id="@+id/etBookName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="4dp"android:layout_marginLeft="4dp"android:ems="10"android:hint="输入要查询的书名"android:inputType="textPersonName"app:layout_constraintBottom_toBottomOf="@+id/textView5"app:layout_constraintStart_toEndOf="@+id/textView5"app:layout_constraintTop_toTopOf="@+id/textView5"app:layout_constraintVertical_bias="0.538" /></androidx.constraintlayout.widget.ConstraintLayout>

核心代码:

public class FirstFragment extends Fragment {private FragmentFirstBinding binding;private boolean islogin=false;private IMyBookManager bookManager = null;private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d("jackie","client,onServiceConnected");bookManager = IMyBookManager.Stub.asInterface(service);Toast.makeText(getContext(), "服务连接成功!", Toast.LENGTH_SHORT).show();}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.d("jackie","client,onServiceDisconnected");bookManager = null;}};@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {binding = FragmentFirstBinding.inflate(inflater, container, false);return binding.getRoot();}private void connect() {binding.btnConnection.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d("jackie","client,btnConnection click");if (bookManager != null) {Log.d("jackie","client,btnConnection click bookManager != null");Toast.makeText(getContext(), "服务连接成功!", Toast.LENGTH_SHORT).show();} else {Log.d("jackie","client,btnConnection click bookManager == null");Intent intent = new Intent();intent.setAction("com.ze.aidlservice.bookService");intent.setPackage("com.ze.aidlservice");
//                    intent.setComponent(new ComponentName("com.yunzhou.aidlserver", "com.yunzhou.aidlserver.MyAidlService"));
//                    intent.setComponent(new ComponentName("com.ze.aidlservice","com.ze.aidlservice.Service.AIDLService"));
//                    getContext().bindService(intent, conn, Context.BIND_AUTO_CREATE);boolean isConnet = getContext().bindService(intent, conn, Context.BIND_AUTO_CREATE);Log.d("jackie","isConnet:::"+isConnet);}}});binding.btnLogin.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(bookManager == null){Toast.makeText(getContext(), "还没有绑定服务!", Toast.LENGTH_SHORT).show();return;}if(binding.etName.getText().toString().isEmpty() || binding.etPwd.getText().toString().isEmpty()){Toast.makeText(getContext(), "用户名或密码不能为空!", Toast.LENGTH_SHORT).show();return;}try {String resStr = bookManager.login(binding.etName.getText().toString(),binding.etPwd.getText().toString());if(resStr.compareToIgnoreCase("success") == 0){islogin=true;Toast.makeText(getContext(), "登录成功!", Toast.LENGTH_SHORT).show();} else{Toast.makeText(getContext(), "登录失败!", Toast.LENGTH_SHORT).show();throw new RemoteException("登录失败");}} catch (RemoteException e) {e.printStackTrace();Toast.makeText(getContext(), "登录失败!", Toast.LENGTH_SHORT).show();}}});binding.btnQuery.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(bookManager == null && islogin ){Toast.makeText(getContext(), "请先绑定服务并登录!", Toast.LENGTH_LONG).show();return;}if(binding.etBookName.getText().toString().isEmpty()){Toast.makeText(getContext(), "请输入您要查找的图书!", Toast.LENGTH_LONG).show();return;}try {Book book = bookManager.queryByName(binding.etBookName.getText().toString());String price = bookManager.getBookPrice("jackie");if(book != null){binding.tvBookInfo.append(book.toString());//                       binding.tvBookInfo.append(price);} else{throw new RemoteException("查询失败!");}} catch (RemoteException e) {e.printStackTrace();binding.tvBookInfo.append("查询失败!");}}});}public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);connect();}@Overridepublic void onDestroyView() {super.onDestroyView();binding = null;}}

测试结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们说一下定向tag:
AIDL 定义的接口文件,使用 in、out、inout 方向标签表明数据流向:

原始类型、String、IBinder 参数以及 AIDL 生成的接口参数 只能 用 in 修饰,可以不显式地写出来。
其他类型参数,主要是 Parcel 类型和 List、Map 类型,支持 out、inout,必须显式写出来。
大家只要自己试一下这些参数,并 Build 生成下 Java 文件,就可以发现它们的区别:

  • in:Proxy 端流向 Stub 端,Proxy 端将数据写入 Parcel,通过 BinderDriver 后,Stub 端从 Parcel 中读取。
  • out:Stub 端流向 Proxy 端,Proxy 端不传递此参数,Stub 端创建实例,执行方法后,将更新后的参数写入 Parcel,Proxy 端从 Parcel 中先读取 Reply,再读取更新后的参数。
  • inout:Proxy 端写入,Stub 端读取后,执行方法,将更新后的参数传回,Proxy 再读取更新后的参数。
    可以参考「Android Binder」AIDL中的 in / out 到底是啥?

最后在强调一下:
从Android 11 开始 系统对app的可见性进行了保护,只有部分应用可见所有app。如果系统是11以上,需要在AndroidManifest里面声明queries,要不然客户端会拉不起服务。

讲到这里基本使用已经讲完,喜欢的点赞支持!

相关文章:

【Android AIDL之详细使用】

Android AIDL之详细使用一级目录概述使用场景语法相关编码实践服务端&#xff1a;java文件修改AndroidManifest客户端坑一级目录 概述 AIDL叫Android接口定义语言&#xff0c;是用于辅助开发者完成Android跨进程编程的工具。 从某种意义上说AIDL其实是一个模板&#xff0c;因…...

ASP.NET MVC | 简介

目录 前提 1.教程 2.MVC 编程模式 最后 前提 在学习学过很多课程&#xff0c;但是最主要学的还是ASP.NET MVC这门课程&#xff0c;工作也是用的ASP.NET MVC&#xff0c;所以写一点ASP.NET MVC的东西&#xff0c;大家可以来看看&#xff0c;我自己不会的时候也不用找别的地方…...

95后刚毕业2、3年就年薪50W,才发现,打败我们的不是年龄····

一刷朋友圈&#xff0c;一读公众号&#xff0c;一打开微博&#xff0c;甚至是一和朋友聊天&#xff0c;这些让人焦虑的话题总会铺天盖地的袭来&#xff1a; Ta刚毕业半年&#xff0c;就升职加薪当上了测试主管 &#xff08;同样是一天24小时&#xff0c;为什么同龄人正在抛弃…...

动态分析和静态分析最主要的区别是什么?

动态分析和静态分析主要的区别是什么&#xff1f; 动态分析和静态分析的主要区别是是否考虑时间因素。 动态分析&#xff08;dynamic analysis&#xff09;是相对于静态分析来讲的&#xff0c;动态分析是只改变一下自变量&#xff0c;因变量相应的做出的改变&#xff0c;动态改…...

WebUI 学习笔记

WebUI 学习笔记 背景此插件主要用于在数字孪生方向做 UI 显示的效果。比如一些温度曲线需要显示出来,可以直接用插件,配合html 文件,直接显示出来。 准备工作我们采用4.27 版本进行开发;...

C# 中常见的设计模式附带代码案例

设计模式是一套被广泛应用于软件设计的最佳实践&#xff0c;它们可以帮助开发者解决特定的问题&#xff0c;提高代码的可重用性、可读性和可维护性。本文将介绍 C# 中常见的几种设计模式&#xff0c;并提供相应的示例代码。 工厂模式 工厂模式是一种创建型设计模式&#xff0c…...

秋招面试问题整理之机器学习篇

文章目录随机森林在决策树的哪些方面做出了改进随机森林里每棵树的权重不一定会变成什么模型方差和偏差&#xff0c;正则化解决的是方差大还是偏差大的问题正则化的方法总结了解VC维吗svd了解吗随机森林在决策树的哪些方面做出了改进 回答思路&#xff1a; 随机森林和决策树有…...

SuperMap超图使用简单笔记

1 需求&#xff1a; 项目使用的是openlayer和Cesium&#xff0c;现在需要使用超图的图层&#xff0c;和引入实景公路功能。 2 使用过程中出现一下疑问点记录如下 &#xff1a; 超图&#xff1a; 北京超图软件股份有限公司是全球第三大、亚洲最大的地理信息系统&#xff08;G…...

从0探索NLP——神经网络

从0探索NLP——神经网络 1.前言 一提人工智能&#xff0c;最能想到的就是神经网络&#xff0c;但其实神经网络只是深度学习的主要实现方式。 现在主流的NLP相关任务、模型大都是基于深度学习也就是构建神经网络实现的&#xff0c;所以这里讲解一下神经网络以及简单的神经网络…...

计算机操作系统和进程

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; ✨每日一语&#xff1a;心平能愈三千疾&#xff0c;心静可通万事理。 目 录&#x1f42c;一. 操作系统&#x1f366;1. 操作系统是什么&#xff1f;&#x1f368;2. 操作系统的两个…...

JAVA服务端实现页面截屏(附代码)

JAVA服务端实现页面截屏适配需求方案一、使用JxBrowser使用步骤&#xff1a;方案二、JavaFX WebView使用步骤&#xff1a;方案三、Headless Chrome使用步骤&#xff1a;综上方案对比记录我的一个失败方案参考适配需求 有正确完整的地址url&#xff1b;通过浏览器能打开该url对…...

Java入门要知道!

首先我们都知道的是Java是一门面向对象的编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表&#xff0c;极好地实现了面向…...

[6/101] 101次软件测试面试之经典面试题剖析

01、自我介绍答&#xff1a;大家好&#xff0c;我是一名软件测试工程师&#xff0c;但我更喜欢称自己为“软件bug捕手”。我相信&#xff0c;软件测试工程师的使命就是让软件更加健壮、更加可靠、更加美好。我们就像是一群“特警”&#xff0c;在黑暗的代码中寻找漏洞和缺陷&am…...

电脑c盘满了变成红色了怎么清理,清理c盘详细攻略

我们的电脑当用了一段时间之后&#xff0c;其实自然而然的就会有一点点卡&#xff0c;其实这是因为我们的电脑c盘满了&#xff0c;所以会造成卡顿是正常的&#xff0c;今天我们就来聊一聊电脑c盘满了变成红色了怎么清理&#xff1f; 一.电脑c盘为啥会满 软件安装&#xff1a;当…...

现在的00后,实在是太卷了

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…...

RocketMQ概述

RocketMQ入门学习MQ概述MQ简介MO用途限流削峰异步解耦数据收集常见的MQ产品ActiveMQRabbitMQKafkaRocketMQ对比MQ常见协议JMSSTOMPAMOPMQTTMQ概述 MQ简介 MQ&#xff0c;Message Queue&#xff0c;是一种提供消息队列服务的中间件&#xff0c;也称为消息中间件&#xff0c;是…...

解决Ubuntu22.04.1上安装ch34x串口驱动报 Key was rejected by service 需要签名的问题

解决Ubuntu22.04.1上安装ch34x串口驱动报 Key was rejected by service 需要签名的问题问题官网下载解压驱动包编译安装给驱动签名再来载入模块&#xff08;设备驱动程序&#xff09;问题 Ubuntu22.04.1 Linux版本5.19.0-32-generic 运行Qt串口通信 m_serialPort->open(QIO…...

[python入门㊿] - python如何打断点

目录 ❤ 什么是bug(缺陷) ❤ python代码的调试方式 ❤ 使用 pdb 进行调试 测试代码示例 利用 pdb 调试 退出 debug debug 过程中打印变量 停止 debug 继续执行程序 debug 过程中显示代码 使用函数的例子 对函数进行 debug 在调试的时候动态改变值 ❤ 使用 PyC…...

CCNP350-401学习笔记(501-550题)

501、Refer to the exhibit. What is the effect of the configuration? A. The device will allow users at 192.168.0.202 to connect to vty lines 0 through 4 using the password ciscotestkey B. The device will allow only users at 192 168.0.202 to connect to vty …...

音箱上8键触摸芯片绿芯GTC08L完美替换启攀微

由工采网代理提供的韩国GreenChip电容式触摸芯片-GTC08L是GreenTouch5CTM电容式触摸传感器系列之一&#xff1b;可以在发动机运行下进行8通道电容传感&#xff1b;对电磁兼容、电磁干扰、温湿度变化、电压干扰、温度漂移、湿度漂移等都有较强的抗干扰能力。不会对CS, RS,EFT&am…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...