AIDL:Android Interface Definition Language,即Android接口定义语言。

他的作用大家已经知道了,有些童鞋对于其中的使用细节可能会有一些理解误差,并且会造成一些异常或者通讯失败。

我们先看几个关键点再看代码,如果项目不符合这几点,肯定会造成通讯失败或异常:

1、客户端、服务端的aidl文件必须包名一致,以下错误就是这个问题引起的,

java.lang.SecurityException: Binder invocation to an incorrect interface

2、可以自定义类型

但是aidl路径中的类型文件,比如main/aidl包下的一个类型文件com.demo.aidl.bean.TestBean.aidl,必须在main/java 包下创建一个同路径的文件,并且实现Parcelable接口,也就是com.demo.aidl.bean.TestBean.java。TestBean.aidl文件内只需要写两行代码

第一行跟普通java文件一样,文件路径,第二行相当于一个声明package com.jiao.aidlservicedemo.bean;parcelable TestBean;

Java同路径文件内容则是跟平常写代码一样,

package com.jiao.aidlservicedemo.bean;import android.os.Parcelable;public class TestBean implements Parcelable {
...
}

3、 绑定服务:

因为是不同项目,跨进程了,并且提供服务端Service(Sevice通讯核心组件)代码也不在用一项目中,所以要注意绑定服务的方式

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.jiao.aidlservicedemo", "com.jiao.aidlservicedemo.TalksService"));
intent.setAction("com.jiao.aidlservicedemo.TalksService.aidl");
bindService(intent, conn, BIND_AUTO_CREATE);

ComponentName 里面两个参数

        Param1:所要通讯的项目(Service端)包名,也就是applicationId,一般与AndroidManifest.xml 中最外层标签 <manifest package="com.jiao.aidlclientdemo">中的package的值相同,但是如果在module里面的build.gradle中 applicationId 的值与项目包名不一致,则使用applicationId。

        Param2:Service端的Service 组件的路径+文件名(无后缀)

Param3:setAction

这个是组件Service在清单文件AndroidManifest.xml中注册时的<action android:name=“”>,如:

 <serviceandroid:name=".TalksService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.jiao.aidlservicedemo.TalksService.aidl" /></intent-filter></service>
enabled、exported,两个属性要为true

4、Android 11 及以上系统 跨应用通讯

想通讯需要让客户端知道手机上是否有服务端这项目,此时需要在客户端的清单文件中注册一下权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.jiao.aidlclientdemo"><!--    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"--><!--        tools:ignore="QueryAllPackagesPermission" />--><queries><package android:name="com.jiao.aidlservicedemo" /></queries>
<application>
...
</application>

两种方法 ,第一种获取手机中安装APP列表权限,第二种比较安全一点,只是用<queries>申请一下服务端这个项目的安装情况<queries> 中可以写多个包名,里面package 的值,是Service所在的包名或者applicationId。

Demo代码

项目 结构图  (ITalkAidlInterface.aidl为aidl核心类,IServiceCallback.aidl回调接口,TalkContent.aidl数据模型)

ITalkAidlInterface.aidl

// ITalkAidlInterface.aidl
package com.jiao.aidlservicedemo;// Declare any non-default types here with import statements
import com.jiao.aidlservicedemo.bean.TalkContent;
import com.jiao.aidlservicedemo.IServiceCallback;interface ITalkAidlInterface {/***   接收消息*/void leavingMessage(in TalkContent talk);/**** 提供消息*/void getAllTalks( IServiceCallback iServicecallBack);
}

IServiceCallback.aidl

// IServiceCallback.aidl
package com.jiao.aidlservicedemo;interface IServiceCallback {void taks(inout Map talks);
}

TalkContent.aidl

// TalkContent.aidl
package com.jiao.aidlservicedemo.bean;parcelable TalkContent;

以上是aidl代码,客户端服务端都一样,可以直接复制过去,aidl部分写完之后,需要 编译一下项目 Make Prokect,自动生成一些文件到build中,然后开始写业务代码。

TalkContent

package com.jiao.aidlservicedemo.bean;import android.os.Parcel;
import android.os.Parcelable;/*** @author: jiaojunfeng* @date: 1/10/23* @describe:*/
public class TalkContent implements Parcelable {private String talkContent;private String id;private String name;public TalkContent(String talkContent, String id, String name) {this.talkContent = talkContent;this.id = id;this.name = name;}public String getTalkContent() {return talkContent;}public void setTalkContent(String talkContent) {this.talkContent = talkContent;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}protected TalkContent(Parcel in) {talkContent = in.readString();id = in.readString();name = in.readString();}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(talkContent);dest.writeString(id);dest.writeString(name);}@Overridepublic int describeContents() {return 0;}public static final Creator<TalkContent> CREATOR = new Creator<TalkContent>() {@Overridepublic TalkContent createFromParcel(Parcel in) {return new TalkContent(in);}@Overridepublic TalkContent[] newArray(int size) {return new TalkContent[size];}};@Overridepublic String toString() {return "TalkContent{" +"talkContent='" + talkContent + '\'' +", id='" + id + '\'' +", name='" + name + '\'' +'}';}
}

服务端主要代码(MainActivity中没业务代码,可以忽略)

TalksService.java

package com.jiao.aidlservicedemo;import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;import com.jiao.aidlservicedemo.bean.TalkContent;import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;import androidx.annotation.Nullable;/*** @author: jiaojunfeng* @date: 1/10/23* @describe:*/
public class TalksService extends Service {private BinderService iTalkAidlInterface;@Overridepublic void onCreate() {super.onCreate();iTalkAidlInterface = new BinderService(this);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return iTalkAidlInterface;}public static class BinderService extends ITalkAidlInterface.Stub {Context context;public BinderService(Context context) {this.context = context;}@Overridepublic void leavingMessage(TalkContent talk) throws RemoteException {Log.i("TalksService",talk.toString());
//此处是我做了一个本地化持久保存, 可以用arraylist来代替测试          SharedPreferencesUtil.saveTalk(context, talk.getId(), talk);}@Overridepublic void getAllTalks( IServiceCallback iServiceCallback  ) throws RemoteException {
//此处是我做了一个本地化持久保存, 可以用arraylist来代替测试Map<String, ?> map = SharedPreferencesUtil.getTalks(context);iServiceCallback.taks(map);}}
}

客户端代码 主要是MainActivity

MainActivity

package com.jiao.aidlclientdemo;import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;import com.google.gson.Gson;
import com.jiao.aidlservicedemo.IServiceCallback;
import com.jiao.aidlservicedemo.ITalkAidlInterface;
import com.jiao.aidlservicedemo.bean.TalkContent;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private LinearLayout llyControl;private TextView tvBind;private TextView tvAdd;private TextView tvGet;private EditText etEditContent;private ListView lvHistory;Intent intent;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private ITalkAidlInterface iPersonManager;ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {Log.d("MainActivity", "onServiceConnected: ");iPersonManager = ITalkAidlInterface.Stub.asInterface(iBinder);}@Overridepublic void onServiceDisconnected(ComponentName componentName) {Log.d("MainActivity", "onServiceDisconnected  ");iPersonManager = null;}};ArrayList<TalkContent> arrayList = new ArrayList<>();Talksadapter talksadapter;private void initView() {llyControl = findViewById(R.id.lly_control);tvBind = findViewById(R.id.tv_bind);tvAdd = findViewById(R.id.tv_add);tvGet = findViewById(R.id.tv_get);etEditContent = findViewById(R.id.et_edit_content);lvHistory = findViewById(R.id.lv_history);talksadapter = new Talksadapter(this, arrayList);lvHistory.setAdapter(talksadapter);tvBind.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//如果是两个project,则客户端需用隐式调用,setPackage、setAction等
//        Intent intent1 = new Intent(getApplicationContext(), MyAidlService.class);
//        bindService(intent1, mConnection, BIND_AUTO_CREATE);intent = new Intent();intent.setComponent(new ComponentName("com.jiao.aidlservicedemo", "com.jiao.aidlservicedemo.TalksService"));
//        intent.setPackage("com.jiao.aidlservicedemo");intent.setAction("com.jiao.aidlservicedemo.TalksService.aidl");boolean isBind = bindService(intent, conn, BIND_AUTO_CREATE);Log.d("MainActivity", "isBind= " + isBind);}});tvGet.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (iPersonManager != null) {
//try {iPersonManager.getAllTalks(new IServiceCallback.Stub() {@Overridepublic void taks(Map talks) throws RemoteException {HashMap<String, Set> talkContentHashMap = (HashMap<String, Set>) talks;for (String str : talkContentHashMap.keySet()) {Set<String> talkContent = talkContentHashMap.get(str);if (talkContent != null) {for (String talkC : talkContent) {arrayList.add(new Gson().fromJson(talkC, TalkContent.class));}}talksadapter.notifyDataSetChanged();}}});} catch (RemoteException e) {e.printStackTrace();}}}});tvAdd.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {if (iPersonManager != null) {iPersonManager.leavingMessage(new TalkContent("hallo", "001", "张三"));} else {Log.d("MainActivity", "tvAdd iPersonManager=null ");}} catch (RemoteException e) {e.printStackTrace();}}});}
}

Talksadapter

package com.jiao.aidlclientdemo;import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;import com.jiao.aidlservicedemo.bean.TalkContent;import java.util.ArrayList;/*** @author: jiaojunfeng* @date: 1/11/23* @describe:*/
public class Talksadapter extends BaseAdapter {private Context context;private ArrayList<TalkContent> arrayList;public Talksadapter(Context context, ArrayList<TalkContent> arrayList) {this.context = context;this.arrayList = arrayList;}@Overridepublic int getCount() {return arrayList.size();}@Overridepublic Object getItem(int position) {return arrayList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {convertView = View.inflate(context, R.layout.adapter_talks_item, null);TextView tvContent = convertView.findViewById(R.id.tv_content);TextView tvName = convertView.findViewById(R.id.tv_name);Log.d("MainActivity", "arrayList.get(position)=" + arrayList.get(position));TalkContent talkContent = arrayList.get(position);try {if (talkContent != null) {String content = talkContent.getTalkContent();tvContent.setText(content);tvName.setText(talkContent.getName());}} catch (Exception e) {}return convertView;}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity"><LinearLayoutandroid:id="@+id/lly_control"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_bind"android:layout_width="wrap_content"android:layout_height="50dp"android:background="@color/colorAccent"android:gravity="center"android:padding="10dp"android:text="绑定" /><TextViewandroid:id="@+id/tv_add"android:layout_width="wrap_content"android:layout_height="50dp"android:layout_marginLeft="5dp"android:background="@color/colorAccent"android:gravity="center"android:padding="10dp"android:text="添加数据" /><TextViewandroid:id="@+id/tv_get"android:layout_width="wrap_content"android:layout_height="50dp"android:layout_marginLeft="5dp"android:background="@color/colorAccent"android:gravity="center"android:padding="10dp"android:text="获取数据" /></LinearLayout><EditTextandroid:id="@+id/et_edit_content"android:layout_width="match_parent"android:layout_height="60dp"android:layout_alignParentBottom="true"android:hint="请输入对话内容" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@+id/et_edit_content"android:layout_below="@+id/lly_control"><ListViewandroid:id="@+id/lv_history"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout></RelativeLayout>

adapter_talks_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/tv_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:minHeight="50dp"android:paddingLeft="4dp"android:textColor="#000000"android:textSize="14sp" /><TextViewandroid:id="@+id/tv_content"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:minHeight="50dp"android:paddingLeft="14dp"android:textColor="#000000"android:textSize="14sp" />
</LinearLayout>

服务端清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"package="com.jiao.aidlservicedemo"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><!--        // enabled 是否可以被系统实例化,--><!--        // 默认为 true 因为父标签 也有 enable 属性,--><!--        // 所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。--><!--       --><!--        // exported 是否支持其它应用调用当前组件。--><!--        // 默认值:如果包含有intent-filter 默认值为true;--><!--        // 没有intent-filter默认值为false。--><!--            //该Service可以响应带有com.bard.gplearning.IMyAidlInterface这个action的Intent。--><!--            //此处Intent的action必须写成“服务器端包名.aidl文件名”--><serviceandroid:name=".TalksService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.jiao.aidlservicedemo.TalksService.aidl" /></intent-filter></service></application></manifest>

客户端清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.jiao.aidlclientdemo"><!--    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"--><!--        tools:ignore="QueryAllPackagesPermission" />--><queries><package android:name="com.jiao.aidlservicedemo" /></queries><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><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>

代码 我用到了

implementation 'com.squareup.retrofit2:converter-gson:2.0.0'

文中若有缺失或不对的地方 欢迎指证,谢谢!

AIDL 应用间简单通信demo及基本问题相关推荐

  1. DSP与FPGA间简单通信时序

    DSP与FPGA采用EMIF接口通信,即将FPGA作为DSP的外部SRAM,只需设置EMIF控制的存储器为SRAM类型即可,DSP通过EMIF接口读写SRAM的时序如下: 参考datasheet< ...

  2. Android 使用AIDL实现进程间的通信

    在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成. AIDL(android Interface Definition Language)是一种接口定义语言,编译器通 ...

  3. 使用AIDL实现进程间的通信之复杂类型传递

    上次讲到简单的AIDL进程间通信的操作,客户端向服务端发送一个String类型的参数,服务端也返回一个String类型的结果,看似已经可以完成基本的需要了.不过在有的时候,简单的数据类型并不能满足我们 ...

  4. 使用AIDL实现进程间的通信

    在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成. AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通 ...

  5. access下如何配置两个vlan_不同vlan间的通信如何简单配置(三种方式) ?

    1.单臂路由(图) 环境:一台路由器,一台二层交换机,两台pc机 二层交换机的配置 一般模式: Switch> 输入enable进入特权模式: Switch>enable 输入config ...

  6. python与android交互,Android客户端与Python服务器端的简单通信

    最近在做一个APP,需要与服务器通信,一点一点的尝试,记录一下. 本文使用了OkHttp和Flask框架. Android客户端: 实现功能输入完点击OK按钮后会toast成功的信息. Python服 ...

  7. 多线程进阶(五)--线程间的通信

    多线程基础概念:多线程入门(一) 多线程基础实现:多线程入门(二) 多线程管理:多线程基础(三) 线程间的状态转换:多线程基础(四) 本篇我们就简单的介绍下,线程间的通信: 多线程进阶(五)--线程间 ...

  8. Android 使用Messenger和Aidl实现跨进程通信

    Android Messenger和Aidl的使用 1.怎么使用多进程 为安卓的四大组件设置process属性值 例如:android:process=":test"或者 andr ...

  9. Vue全家桶之组件间的通信(四)

    Vue全家桶之组件间的通信(四) 概述 组件是Vue中最强大的功能,组件实例之间的数据无法直接相互引用,所以需要掌握组件间通信的方式和技巧. 组件实例之间的关系可以分为父子关系.兄弟关系和隔代关系.针 ...

最新文章

  1. 【VMC实验室】在QCloud上创建您的SQL Cluster(1)
  2. 后bat时代,字节未来超越at也不是没可能
  3. linux 开启LACP 单端口,linux – 使用FTOS在Force10 S50N上PXE启动LACP主机
  4. Spring Boot系列四 Spring @Value 属性注入使用总结一
  5. jzoj3189-解密【字符串hash】
  6. linux搭建java开发环境_linux中搭建java开发环境
  7. 表单的默认提交方式_对于PHP表单提交有哪集中方式讲解
  8. Fedora下SAMBA的相关配置
  9. 5.2.5 标准的原子整型的相关操作
  10. 1000道Python题库系列分享三(30道)
  11. vue.js中使用甘特图(gantt-elastic)的使用
  12. 你的六岁在玩儿泥巴,他们六岁已经在讲算法了
  13. JavaWeb - 小米商城网 - 项目启动
  14. SumatraPDF的反向搜索
  15. 使用 K-means 算法进行客户分类
  16. EmguCV学习(三)
  17. 高性能服务器编程-信号
  18. PHP“垂死挣扎”的十年!
  19. 银行离岸汇款客户交易预测
  20. CSharp调用Matlab编译的dll

热门文章

  1. 互联网金融神话 余额宝破1853亿的背后
  2. Discuz贴吧楼中楼回复(replyfloor)_Discuz插件
  3. iphone 激活日期查询
  4. 机器人专用符文_一Q一个嘤嘤怪!启封符文机器人黑科技
  5. 龙族幻想每个职业的圣核怎么加呢
  6. 六轴机械臂控制器 控制卡 软件 机械臂
  7. SONY索尼A7S3相机HEVC|H.265视频RSV损坏修复MP4
  8. 基于Arco框架 gaode
  9. 某数美验证码逆向分析
  10. python对象的特性_Python对象的思想和特性,python