1. 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来请求端口,连通后就可以进行通信。
2. Carson带你学Android:全面剖析Binder跨进程通信原理
从而全方位地介绍 Binder ,希望你们会喜欢。
在本文的讲解中,按照 大角度 -> 小角度 去分析 Binder ,即:
从而全方位地介绍 Binder ,希望你们会喜欢。
在讲解 Binder 前,我们先了解一些 Linux 的基础知识
具体请看文章: 操作系统:图文详解 内存映射
Binder 跨进程通信机制 模型 基于 Client - Server 模式
此处重点讲解 Binder 驱动作用中的跨进程通信的原理:
原因:
所以,原理图可表示为以下:
所以,在进行跨进程通信时,开发者只需自定义 Client & Server 进程 并 显式使用上述3个步骤,最终借助 Android 的基本架构功能就可完成进程间通信
注册服务后, Binder 驱动持有 Server 进程创建的 Binder 实体
此时, Client 进程与 Server 进程已经建立了连接
Client 进程 根据获取到的 Service 信息( Binder 代理对象),通过 Binder 驱动 建立与 该 Service 所在 Server 进程通信的链路,并开始使用服务
步骤1: Client 进程 将参数(整数a和b)发送到 Server 进程
步骤2: Server 进程根据 Client 进要求 调用 目标方法(即加法函数)
步骤3: Server 进程 将目标方法的结果(即加法后的结果)返回给 Client 进程
对比 Linux ( Android 基于 Linux )上的其他进程通信方式(管道、消息队列、共享内存、
信号量、 Socket ), Binder 机制的优点有:
特别地,对于从模型结构组成的Binder驱动来说:
不定期分享关于 安卓开发 的干货,追求 短、平、快 ,但 却不缺深度 。
3. Android如何跨进程同步
两个进程要进行同步,如果用IPC机制通信来同步,那么就会遇到一个问题,那就是这两个进程必须都已经启动才可以,如果遇到一个进程启动,但是另外一个进程不知道什么时候启动,这个办法就很难行得通了。
这时候就可以用到Android系统根据java提供的 FileLock 类
1.FileLock是线程安全的
2.FileLock适用于进程间文件读写控制,不适用于同一进程的不同线程
3.分为共享锁和独占锁,共享锁允许其他进程同样获取共享锁,独占锁不允许其他进程获得锁。
4.有两种方式获得文件锁,FileChannel的lock和tryLock,用lock会阻塞当前线程,直到获取到锁,用tryLock会尝试获取,如果获取失败则返回null,不会阻塞线程。
5.FileLock释放的条件是:自己调用release/close或者所使用的FileChannel调用close或者是JVM终止运行。
6.文件锁的效果是与操作系统相关的。一些系统中文件锁是强制性的,当Java的某进程获得文件锁后,操作系统将保证其它进程无法对文件做操作了。而另一些操作系统的文件锁是询问式的(advisory),意思是说要想拥有进程互斥的效果,其它的进程也必须也按照API所规定的那样来申请或者检测文件锁,不然将起不到进程互斥的功能。所以文档里建议将所有系统都当做是询问式系统来处理,这样程序更加安全也更容易移植。
我们这里用的就是独占锁。
这个是先运行的获取锁的类,获取锁后持有10s后释放。
这个类是在第一个类运行后再运行的类,此时该进程会一直等到FileLockTest释放锁后才能获得锁然后继续运行。我们可以在获得锁之后do any thing you want,从而实现进程间同步。
多次运行后可能有人会发现有时候先打印获得锁后打印释放锁,其实是这样的,这是两个进程,一个进程释放锁之后另外一个进程才可能获得锁,但是两个进程的打印时间的执行不是同步的,所以不一定是先打印释放锁,只要时间基本一致即可(本人多次运行时间差小于2ms)。
通过这两个类的分别运行,可以看到即使不是都启动完成,一样可以跨进程同步。
4. 了解Android进程间通信的四种方式
由于应用程序之间不能共享内存。在不同应用程序之间交互数据(跨进程通讯),在android
SDK中提供了4种用于跨进程通讯的方式。这4种方式正好对应于android系统中4种应用程序组
件:Activity、Content Provider、Broadcast和Service。其中Activity可以跨进程调用其他应
用程序的Activity;Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形
式返回),当然,也可以对其他应用程序的数据进行增、删、改操 作;Broadcast可以向
android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;
Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content
Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫
AIDL服务。
5. 安卓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中的所有元素必须是此列表中支持的数据类型)
接口里的方法就是按需求需创建。这里只举几个简单的示例。
6. Android跨进程通信-共享内存
还是先看共享内存的使用方法,我主要介绍两个函数:
通过 shmget() 函数申请共享内存,它的入参如下
通过 shmat() 函数将我们申请到的共享内存映射到自己的用户空间,映射成功会返回地址,有了这个地址,我们就可以随意的读写数据了,我们继续看一下这个函数的入参
共享内存的原理是在内存中单独开辟的一段内存空间,这段内存空间其实就是一个tempfs(临时虚拟文件),tempfs是VFS的一种文件系统,挂载在/dev/shm上,前面提到的管道pipefs也是VFS的一种文件系统。
由于共享的内存空间对使用和接收进程来讲,完全无感知,就像是在自己的内存上读写数据一样,所以也是 效率最高 的一种IPC方式。
上面提到的IPC的方式都是 在内核空间中开辟内存来存储数据 ,写数据时,需要将数据从用户空间拷贝到内核空间,读数据时,需要从内核空间拷贝到自己的用户空间,
共享内存就只需要一次拷贝 ,而且共享内存不是在内核开辟空间,所以可以 传输的数据量大 。
但是 共享内存最大的缺点就是没有并发的控制,我们一般通过信号量配合共享内存使用,进行同步和并发的控制 。
共享内存在Android系统中主要的使用场景是 用来传输大数据 ,并且 Android并没有直接使用Linux原生的共享内存方式,而是设计了Ashmem匿名共享内存 。
之前说到有名管道和匿名管道的区别在于有名管道可以在vfs目录树中查看到这个管道的文件,但是匿名管道不行, 所以匿名共享内存同样也是无法在vfs目录中查看到 的, Android之所以要设计匿名共享内存 ,我觉得主要是为了安全性的考虑吧。
我们来看看共享内存的一个使用场景,在Android中,如果我们想要将当前的界面显示出来,需要将当前界面的图元数据传递Surfaceflinger去做图层混合,图层混合之后的数据会直接送入帧缓存,送入帧缓存后,显卡就会直接取出帧缓存里的图元数据显示了。
那么我们如何将应用的Activity的图元数据传递给SurfaceFlinger呢?想要将图像数据这样比较大的数据跨进程传输,靠binder是不行的,所以这儿便用到匿名共享内存。
从谷歌官方提供的架构图可以看到,图元数据是通过BufferQueue传递到SurfaceFlinger去的,当我们想要绘制图像的时候, 需要从BufferQueue中申请一个Buffer,Buffer会调用Gralloc模块来分配共享内存 当作图元缓冲区存放我们的图元数据。
可以看到Android的匿名共享内存是通过 ashmem_create_region() 函数来申请共享内存的,它会在/dev/ashmem下创建一个虚拟文件,Linux原生共享内存是通过shmget()函数,并会在/dev/shm下创建虚拟文件。
匿名共享内存是通过 mmap() 函数将申请到的内存映射到自己的进程空间,而Linux是通过*shmat()函数。
虽然函数不一样,但是Android的匿名共享内存和Linux的共享内存在本质上是大同小异的。
要使用一块共享内存
7. Android 跨进程通信--Binder篇
话说Binder 其实是由George Hoffman 老哥,在1991年Be公司启动了一个“openBinder”的项目,该项目的宗旨是研究一个高效的信号传递工具,允许多个软件相互合作,构成一个软件系统。在BE被parmSource收购以后,openBinder由hackborn继续开发。在Hackborn加入google之后,他继续开发出了Android Binder。
而Android系统是基于Linux内核实现的,Linux已经提供了多种进程间通信机制,比如:管道、消息队列、共享内存和套接字(Socket)等等。
讲它们优缺点前先补充说明:
“进程隔离”--这个技术是为了避免进程A写入进程B的情况发生。 进程的隔离实现,使用了虚拟地址空间进程A的虚拟地址和进程B的虚拟地址不同,这样就防止进程A将数据信息写入进程B。进程隔离的安全性通过禁止进程间内存的访问可以方便实现。相比之下,一些不安全的操作系统DOS能够允许任何进程对其他进程的内存进行写操作。
“虚拟内存”-- 是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存的使用也更有效率。
注意: 虚拟内存 不只是“用磁盘空间来扩展物理内存”的意思——这只是扩充内存级别以使其包含硬盘驱动器而已。把内存扩展到磁盘只是使用虚拟内存技术的一个结果,它的作用也可以通过覆盖或者把处于不活动状态的程序以及它们的数据全部交换到磁盘上等方式来实现。对虚拟内存的定义是基于对地址空间的重定义的,即把地址空间定义为“连续的虚拟内存地址”,以借此“欺骗”程序,使它们以为自己正在使用一大块的“连续”地址。
8. Android跨进程通信
Android 为我们提供了以下几种进程通信机制(供开发者使用的进程通信 API)对应的文章链接如下:
Android 进阶:进程通信之 Binder 机制浅析
Android 进阶:进程通信之 AIDL 解析
9. android开发中跨进程通信有几种方式
在android SDK中提供了4种用于跨进程通讯的方式,Activity、Content Provider、Broadcast和Service。
介绍
Activity可以跨进程调用其他应用程序;
Content Provider可以跨进程访问其他应用程序中的数据;
Broadcast可以向android系统中所有应用程序发送广播;
Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务;
10. Android 使用Messenger实现跨进程之间通信
以前讲到跨进程通信,我们总是第一时间想到AIDL(Android接口定义语言),实际上,使用Messenger在很多情况下是比使用AIDL简单得多的。
大家看到Messenger可能会很轻易的联想到Message,然后很自然的进一步联想到Handler——没错,Messenger的核心其实就是Message以及Handler来进行线程间的通信。
以下是如何使用Messenger的步骤:
综上六步就能完成客户端与Service的跨进程双向通信过程:
客户端 -> Service -> 客户端
简单的例子(客户端向服务器端发送消息,服务器接收):
服务端主要是返给客户端一个IBinder实例,以供服务端构造Messenger,并且处理客户端发送过来的Message。当然,不要忘了要在Manifests文件里面注册.
客户端就主要是发起与服务端的绑定,以及通过onServiceConnected()方法来过去服务端返回来的IBinder,借此构造Messenger,从而可以通过发送Message的方式与服务端进行交互。
服务器接收消息后回复消息给客户端
客户端修改:
客户端需要添加一个handler用于接收消息
服务端修改:
在服务端的handler获取客户端发送的msg.replyTo