❶ android进阶-AIDL之接口注册/解注册
AIDL-基本使用
AIDL-自定义数据类型
AIDL-修饰符in,out,inout
AIDL-重连方法
AIDL-接口注册/解注册
AIDL-连接池
为什么要特意讲解一下接口的注册与取消注册呢,因为在使用AIDL进程跨进程通信的时候, 每次传递的接口对象在内存中的地址都是不一样的 ,所以在注册了之后,无法使用常规的方式去取消, 因为注册和解注册传递的接口地址都不一样 ,系统无法识别
由于上面的问题,AIDL中提供了一个专门解决上述情况的类 RemoteCallbackList ,其工作原理就是:
首先,在前面讲解 AIDL的基本使用 的基础上先增加新的AIDL接口以及注册和解注册方法:
然后就是 RemoteCallbackList 的使用方法了:
注册/解注册很简单
接着是使用接口的方式:
ps: 需要注意的是 beginBroadcast() 方法和 finishBroadcast() 方法 必须配合使用 ,哪怕只是简单的获取集合大小
使用AIDL进行跨进程间通信中,往往我们是需要注册监听,让服务端通知的,但是服务端也必须提供解注册的方法,不然客户端如果离开某个界面不想再接受消息了,虽然直接离开不做处理客户端这边不会出错,但是服务端那边的监听集合还存在之前的,那么就会浪费系统资源,所以有注册监听的时候,最好也要实现解注册的方法
https://github.com/returntolife455/DemoList
《Android开发艺术探索》
❷ Android开发中在哪些场合下会需要使用AIDL
严格来说,线程是共享资源的,所以线程之间是不存在通信的,Android里面的Handle是用来解决异步调用的,这个观念很重要,想明白了,代码也就写的更合理了。
进程之间内存等资源是隔离的,而AIDL,是Android提供的跨进程通信IPC工具Binder的具体使用方法,跟其他Linux跨进程通信(socket,管道,能存共享等)在概念上没啥差。所以要实现跨进程的内存访问(比如数据传输,函数跨进程同步调用等)就需要了AIDL了,当然了AIDL并不是Android中跨进程通信的唯一选择,socket(systemServer进程与zygote进程,pkms调用install进程,MountService与vold进程通信都是通过socket),共享内存(sqlite3查询就用了)等都可以用的,但是没有Binder通过AIDL好用罢了。
❸ 安卓IPC跨进程通讯:AIDL+Retrofit——AndLinker的初步使用
需要用到安卓跨进程通讯,IPC (进程间通信) 的时候,AndLinker是一款Android上的IPC (进程间通信) 库,结合了 AIDL 和 Retrofit 的诸多特性,且可以与 Rxjava 和 RxJava2 的Call Adapters无缝结合使用。
个人简单理解就是:简化AIDL流程的一个第三方库。使用时需要先了解一下AIDL、retrofit。
以普通Java接口代替AIDL接口
像 Retrofit 一样生成远程服务接口的IPC实现
支持的Call Adapters:Call, RxJava Observable, RxJava2 Observable & Flowable
支持远程服务回调机制
支持AIDL的所有数据类型
支持AIDL的所有数据定向tag:in,out,inout
支持AIDL的oneway关键字
在服务端以及客户端的项目根目录的build.gradle中添加jcenter()仓库
在App的build.gradle中添加如下依赖
AndLinker支持AIDL所有数据类型:
Java语言中的所有原始类型 (如:int,long,char,boolean,等等)
String
CharSequence
Parcelable
List (List中的所有元素必须是此列表中支持的数据类型)
Map (Map中的所有元素必须是此列表中支持的数据类型)
接口里的方法就是按需求需创建。这里只举几个简单的示例。
❹ Android跨进程通信
本文整理和引用他人的笔记,旨在个人复习使用。
参考链接:
https://blog.csdn.net/fanleiym/article/details/83894399
https://github.com/274942954/AndroidCollection/blob/master/Docs/Android%E7%9F%A5%E8%AF%86%E7%82%B9%E6%B1%87%E6%80%BB.md#%E8%BF%9B%E7%A8%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F
https://www.kaelli.com/4.html
https://carsonho.blog.csdn.net/article/details/73560642?utm_medium=distribute.pc_relevant.none-task-blog--1.e_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog--1.e_weight
默认情况下,一个app只会运行在一个进程中,进程名为app的包名。
1. 分散内存的占用
Android系统对每个应用进程的内存占用是有限制的,占用内存越大的进程,被系统杀死的可能性就越大。使用多进程可以减少主进程占用的内存,避免OOM问题,降低被系统杀死的概率。
2. 实现多模块
一个成熟的应用一定是多模块化的。项目解耦,模块化,意味着开辟新的进程,有独立的JVM,带来数据解耦。模块之间互不干预,团队并行开发,同时责任分工也很明确。
3. 降低程序奔溃率
子进程崩溃不会影响主进程的运行,能降低程序的崩溃率。
4. 实现一些特殊功能
比如可以实现推送进程,使得主进程退出后,能离线完成消息推送服务。还可以实现守护进程,来唤醒主进程达到保活目的。还可以实现监控进程专门负责上报bug,进而提升用户体验。
android:process 属性的值以冒号开头的就是 私有进程 ,否则就是 公有进程 。当然命名还需要符合规范,不能以数字开头等等。
1. 前台进程
2. 可见进程
3. 服务进程
4. 后台进程
5. 空进程
Android 会将进程评定为它可能达到的最高级别。另外服务于另一进程的进程其级别永远不会低于其所服务的进程。
创建新的进程时会创建新的Application对象,而我们通常在Application的onCreate方法中只是完成一些全局的初始化操作,不需要多次执行。
解决思路:获取当前进程名,判断是否为主进程,只有主进程的时候才执行初始化操作
获取当前进程名的两种方法:
Application中判断是否是主进程(方法1例子):
Serializable 和 Parcelable是数据序列化的两种方式,Android中只有进行序列化过后的对象才能通过intent和Binder传递。
通常序列化后的对象完成传输后,通过反序列化获得的是一个新对象,而不是原来的对象。
Serializable是java接口,位于java.io的路径下。Serializable的原理就是把Java对象序列化为二进制文件后进行传递。Serializable使用起来非常简单,只需直接实现该接口就可以了。
Parcelable是Google为了解决Serializable效率低下的问题,为Android特意设计的一个接口。Parcelable的原理是将一个对象完全分解,分解成可以传输的数据类型(如基本数据类型)再进行传递。
通常需要存到本地磁盘的数据就使用Serializable,其他情况就使用效率更高的Parcelable。
IPC 即 Inter-Process Communication (进程间通信)。Android 基于 Linux,而 Linux 出于安全考虑,不同进程间不能之间操作对方的数据,这叫做“进程隔离”。
每个进程的虚拟内存空间(进程空间)又被分为了 用户空间和内核空间 , 进程只能访问自身用户空间,只有操作系统能访问内核空间。
由于进程只能访问自身用户空间,因此在传统的IPC中,发送进程需要通过_from_user(系统调用)将数据从自身用户空间拷贝到内核空间,再由接受进程通过_to_user从内核空间复拷贝到自身用户空间,共需要拷贝2次,效率十分低下。Android采用的是Binder作为IPC的机制,只需复制一次。
Binder翻译过来是粘合剂,是进程之间的粘合剂。
Binder IPC通信的底层原理是 通过内存映射(mmap),将接收进程的用户空间映射到内核空间 ,有了这个映射关系,接收进程就能通过用户空间的地址获得内核空间的数据,这样只需发送进程将数据拷贝到内核空间就可完成通讯。
一次完整的Binder IPC通信:
从IPC的角度看,Binder是一种跨进程通信机制(一种模型),Binder 是基于 C/S 架构的,这个通信机制中主要涉及四个角色:Client、Server、ServiceManager和Binder驱动。
Client、Server、ServiceManager都是运行在用户空间的进程,他们通过系统调用(open、mmap 和 ioctl)来访问设备文件/dev/binder,从而实现与Binder驱动的交互。Binder驱动提供进程间通信的能力(负责完成一些底层操作,比如开辟数据接受缓存区等),是Client、Server和ServiceManager之间的桥梁。
Client、Server就是需要进行通信两个的进程,通信流程:
细心的你一定发现了,注册服务和获得服务本身就是和ServiceManager进行跨进程通信。其实和ServiceManager的通信的过程也是获取Binder对象(早已创建在Binder驱动中,携带了注册和查询服务等接口方法)来使用,所有需要和ServiceManager通信的进程,只需通过0号引用,就可以获得这个Binder对象了。
AIDL内部原理就是基于Binder的,可以借此来分析Binder的使用。
AIDL是接口定义语言,简短的几句话就能定义好一个复杂的、内部有一定功能的java接口。
先看看ICallBack.aidl文件,这里定义了一个接口,表示了服务端提供的功能。
被定义出来的java接口继承了IInterface接口,并且内部提供了一个Stub抽象类给服务端(相当于封装了一下,服务端只需继承这个类,然后完成功能的里面具体的实现)。
参考: https://www.cnblogs.com/sqchen/p/10660939.html
(以下是添加了回调的最终实现,可以看参考链接一步一步来)
为需要使用的类,创建aidl文件。
系统会自动在main文件下生成aidl文件夹,并在该文件夹下创建相应目录。
在java相同路径下创建Student类,这里不能使用@Parcelize注解,否则会报错
创建IStudentService.aidl,定义了一个接口,该接口定义了服务端提供的功能。创建完后rebuild一下项目 (每次创建和修改定义接口文件都要rebuild一下)
创建在服务端的StudentService
可以看见有回调,说明客户端也提供了接口给服务端来回调(双向通信,此时客户端的变成了服务端),即ICallBack.aidl
客户端是通过Binder驱动返回的Binder调用StudentService里的具体实现方法
AIDL使用注意:
Messenger可以在不同进程中传递 Message 对象,在Message中放入我们需要传递的数据,就可以轻松地实现数据的进程间传递了。Messenger 是一种轻量级的 IPC 方案,是对AIDL的封装,底层实现是 AIDL。
使用详见: https://blog.csdn.net/qq951127336/article/details/90678698
❺ Android开发艺术探索读书笔记之AIDL
AIDL是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
AIDL可以实现跨进程的方法调用。定义进程通信接口供服务端和客户端调用。
在AIDL文件中并不是所有数据类型都可以使用。只支持下列数据类型
默认情况下AIDL的调用过程是同步的,所以不能直接进行比较耗时的操作,否则容易导致客户端ANR。如果需要进行异步操作,在服务端不需要另起线程,但是在客户端需要另起线程访问远程方法,再通过Handler通知到UI线程即可!
❻ 利用Messenger跨进程通信
Android笔记多进程通信之利用Messenger跨进程通信,
提起跨进程通信,大多数人首先会想到AIDL,AIDL,中文名称是android接口描述语言,是android系统中用于进行跨进程通信必须了解的。其实messenger和AIDL作用一样,都可以进行进程间通讯。它是基于消息的进程间通信,通过构建Message来在客户端和服务端之间传递数据,就像Handler发送消息在子线程和UI线程发送消息那样,还不用去写AIDL文件。
Messenger翻译为信使,可以在不同进程中传递Message对象,在Message中放入我们需要传递的信息,然后通过Messenger将Message传递给对方,就可以轻轻松松实现跨进程数据传递。实际上Messenger是一种轻量级的IPC(跨进程通信)方式,它的底层仍然是实现的AIDL。
此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信;甚至作为一个转接处,任意两个进程都能通过服务端进行通信。
相同点:
1.都与IPC的调用有关;
2.Messenger 是一种轻量级的 IPC方案,底层实现了AIDL,只是进行了封装,开发的时候不用写.aidl文件。
3.都支持实时通信;
不同点:
1. Messenger一次只能处理一个请求(串行)/AIDL一次可以处理多个请求(并行);
当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。
2. Messenger不支持RPC,只能通过message传递消息/AIDL支持RPC;
3. Messenger使用简单,轻量级,不需要创建AIDL文件/AIDL使用复杂,需要创建AIDL文件;
服务端:
1.创建一个handler对象,并实现hanlemessage方法,用于接收来自客户端的消息,并作处理
2.创建一个messenger,封装handler
3.用messenger的getBinder()方法获取一个IBinder对象,通过onBind返回给客户端
客户端:
1.在activity中绑定服务
2.创建ServiceConnection并在其中使用 IBinder 将 Messenger实例化
3.使用Messenger向服务端发送消息,或需要服务器端返回消息,需要创建一个messenger,封装handler,并将这个messenger传递给服务器端。在handler中接收服务器消息。这样就实现了客户端和服务端的双向通信了。
4.解绑服务
5.服务端中在 handleMessage() 方法中接收每个 Message
创建一个service
注册service,当然要设置在不同的进程
注意:Service在声明时必须对外开放,即android:exported="true"
客户端是通过绑定服务端返回的binder来创建Messenger对象,并通过这个Messenger对象来向服务端发送消息。
总结
Message中的Bundle支持多种数据类型,replyTo字段用于传输Messager对象,以便进程间相互通信
Messager以串行的方式处理客户端发来的消息,不适合有大量并发的请求
Messager方法只能传递消息,不能跨进程调用方法
❼ android开发中跨进程通信有几种方式
Android进程间通信的几种方式 定义多进程
第一:Android应用中使用多进程只有一个办法(用NDK的fork来做除外),就是在AndroidManifest.xml中声明组件时,用android:process属性来指定。
不知定process属性,则默认运行在主进程中,主进程名字为包名。
android:process = package:remote,将运行在package:remote进程中,属于全局进程,其他具有相同shareUID与签名的APP可以跑在这个进程中。
android:process = :remote ,将运行在默认包名:remote进程中,而且是APP的私有进程,不允许其他APP的组件来访问。
第二:多进程引发的问题
静态成员和单例失效:每个进程保持各自的静态成员和单例,相互独立。
线程同步机制失效:每个进程有自己的线程锁。
SharedPreferences可靠性下降:不支持并发写,会出现脏数据。
Application多次创建:不同进程跑在不同虚拟机,每个虚拟机启动会创建自己的Application,自定义Application时生命周期会混乱。
综上,不同进程拥有各自独立的虚拟机,Application,内存空间,由此引发一系列问题。
第三: 进程间通信
Bundle/Intent传递数据:
可传递基本类型,String,实现了Serializable或Parcellable接口的数据结构。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者代码量少(仅一句),但I/O开销较大,一般用于输出到磁盘或网卡;后者实现代码多,效率高,一般用户内存间序列化和反序列化传输。
文件共享:
对同一个文件先后写读,从而实现传输,Linux机制下,可以对文件并发写,所以要注意同步。顺便一提,Windows下不支持并发读或写。
Messenger:
Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。
双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。
AIDL:
AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。
通过编写aidl文件来设计想要暴露的接口,编译后会自动生成响应的java文件,服务器将接口的具体实现写在Stub中,用iBinder对象传递给客户端,客户端bindService的时候,用asInterface的形式将iBinder还原成接口,再调用其中的方法。
ContentProvider:
系统四大组件之一,底层也是Binder实现,主要用来为其他APP提供数据,可以说天生就是为进程通信而生的。自己实现一个ContentProvider需要实现6个方法,其中onCreate是主线程中回调的,其他方法是运行在Binder之中的。自定义的ContentProvider注册时要提供authorities属性,应用需要访问的时候将属性包装成Uri.parse("content://authorities")。还可以设置permission,readPermission,writePermission来设置权限。 ContentProvider有query,delete,insert等方法,看起来貌似是一个数据库管理类,但其实可以用文件,内存数据等等一切来充当数据源,query返回的是一个Cursor,可以自定义继承AbstractCursor的类来实现。
Socket:
学过计算机网络的对Socket不陌生,所以不需要详细讲述。只需要注意,Android不允许在主线程中请求网络,而且请求网络必须要注意声明相应的permission。然后,在服务器中定义ServerSocket来监听端口,客户端使用Socket来请求端口,连通后就可以进行通信。
❽ android开发aidl何时使用
1.什么是aidl:aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
icp:interprocess communication :内部进程通信
2.既然aidl可以定义并实现进程通信,那么我们怎么使用它呢?文档/android-sdk/docs/guide/developing/tools/aidl.html中对步骤作了详细描述:
--1.Create your .aidl file - This file defines an interface (YourInterface.aidl) that defines the methods and fields available to a client.
创建你的aidl文件,我在后面给出了一个例子,它的aidl文件定义如下:写法跟java代码类似,但是这里有一点值得注意的就是它可以引用其它aidl文件中定义的接口,但是不能够引用你的java类文件中定义的接口
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.AIDLActivity;
interface AIDLService {
void registerTestCall(AIDLActivity cb);
void invokCallBack();
}
--2.Add the .aidl file to your makefile - (the ADT Plugin for Eclipse manages this for you). Android includes the compiler, called AIDL, in the tools/ directory.
编译你的aidl文件,这个只要是在eclipse中开发,你的adt插件会像资源文件一样把aidl文件编译成java代码生成在gen文件夹下,不用手动去编译:编译生成AIDLService.java如我例子中代码
--3.Implement your interface methods - The AIDL compiler creates an interface in the Java programming language from your AIDL interface. This interface has an inner abstract class named Stub that inherits the interface (and implements a few additional methods necessary for the IPC call). You must create a class that extends YourInterface.Stub and implements the methods you declared in your .aidl file.
实现你定义aidl接口中的内部抽象类Stub,public static abstract class Stub extends android.os.Binder implements com.cao.android.demos.binder.aidl.AIDLService
Stub类继承了Binder,并继承我们在aidl文件中定义的接口,我们需要实现接口方法,下面是我在例子中实现的Stub类:
private final AIDLService.Stub mBinder = new AIDLService.Stub() {
@Override
public void invokCallBack() throws RemoteException {
Log("AIDLService.invokCallBack");
Rect1 rect = new Rect1();
rect.bottom=-1;
rect.left=-1;
rect.right=1;
rect.top=1;
callback.performAction(rect);
}
@Override
public void registerTestCall(AIDLActivity cb) throws RemoteException {
Log("AIDLService.registerTestCall");
callback = cb;
}
};
Stub翻译成中文是存根的意思,注意Stub对象是在被调用端进程,也就是服务端进程,至此,服务端aidl服务端得编码完成了。
--4.Expose your interface to clients - If you're writing a service, you should extend Service and override Service.onBind(Intent) to return an instance of your class that implements your interface.
第四步告诉你怎么在客户端如何调用服务端得aidl描述的接口对象,doc只告诉我们需要实现Service.onBind(Intent)方法,该方法会返回一个IBinder对象到客户端,绑定服务时不是需要一个ServiceConnection对象么,在没有了解aidl用法前一直不知道它是什么作用,其实他就是用来在客户端绑定service时接收service返回的IBinder对象的:
AIDLService mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log("connect service");
mService = AIDLService.Stub.asInterface(service);
try {
mService.registerTestCall(mCallback);
} catch (RemoteException e) {
}
}
public void onServiceDisconnected(ComponentName className) {
Log("disconnect service");
mService = null;
}
};
mService就是AIDLService对象,具体可以看我后面提供的示例代码,需要注意在客户端需要存一个服务端实现了的aidl接口描述文件,但是客户端只是使用该aidl接口,不需要实现它的Stub类,获取服务端得aidl对象后mService = AIDLService.Stub.asInterface(service);,就可以在客户端使用它了,对mService对象方法的调用不是在客户端执行,而是在服务端执行。
4.aidl中使用java类,需要实现Parcelable接口,并且在定义类相同包下面对类进行声明:
上面我定义了Rect1类
之后你就可以在aidl接口中对该类进行使用了
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.Rect1;
interface AIDLActivity {
void performAction(in Rect1 rect);
}
注意in/out的说明,我这里使用了in表示输入参数,out没有试过,为什么使用in/out暂时没有做深入研究。
转载