Android 跨进程通信大总结
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/111553746
本文出自【赵彦军的博客】
文章目录
- 1、Android进程
- 2、修改Android默认进程
- 3、指定activity、Service进程
- 4、activity进程间通信
- 5、AIDL 简介
- 6、activity、service 进程间通信 AIDL
- 7、AIDL 传递复杂对象
- 8、SharedPreferences 跨进程
- 9、广播跨进程
- 10、ContentProvider跨进程
- 什么是ContentProvider ?
- ContentProvider什么作用?
- ContentProvider原理
- ContentProvider优秀文章链接
- 11、Socket跨进程通信
- 12、文件共享跨进程
- 13、Bundle跨进程
- 14、MMKV
1、Android进程
android {compileSdkVersion 29buildToolsVersion "29.0.3"defaultConfig {applicationId "com.zhaoyanjun"minSdkVersion 16targetSdkVersion 29versionCode 1versionName "1.0"}
}
applicationId 为:com.zhaoyanjun
,那项目运行起来,所有的 activity
、service
默认运行在 com.zhaoyanjun
进程.
工具类:
package com.zhaoyanjun;import java.io.FileInputStream;
import java.io.IOException;/*** @author yanjun.zhao* @time 2020/12/16 11:01 AM* @desc*/
public class Process {/*** 获取当前进程名* @return*/public static String getCurrentProcessName() {FileInputStream in = null;try {String fn = "/proc/self/cmdline";in = new FileInputStream(fn);byte[] buffer = new byte[256];int len = 0;int b;while ((b = in.read()) > 0 && len < buffer.length) {buffer[len++] = (byte) b;}if (len > 0) {String s = new String(buffer, 0, len, "UTF-8");return s;}} catch (Throwable e) {e.printStackTrace();} finally {if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}}return null;}
}
2、修改Android默认进程
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.zhaoyanjun"><applicationandroid:process=":appProcess"android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.RecyclerViewDemo"><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>
在 application 标签下添加 android:process
属性可以修改Android默认的进程名字。进程的名字为:com.zhaoyanjun:appProcess
, 这个修改是全局的,所有 activity 都默认运行在这个进程中。
3、指定activity、Service进程
activity 指定进程
<activityandroid:process=":remote"android:name=".MainActivity2">
</activity>
service 指定进程
<serviceandroid:process=":remote_service"android:name=".LibraryService">
</service>
4、activity进程间通信
MainActivity
有一个 button
按钮,点击跳转到 MainActivity2
//MainActivity代码
findViewById<Button>(R.id.bt1).setOnClickListener {var intent = Intent(this, MainActivity2::class.java)intent.putExtra("key", "value1")startActivity(intent)
}
MainActivity2 指定进程
<activityandroid:process=":remote"android:name=".MainActivity2">
</activity>
MainActivity2 逻辑
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main2)var value = intent.getStringExtra("key")Log.d("zhaoyanjun", "MainActivity2 进程: ${Process.getCurrentProcessName()} 获取值: $value")
}
日志:
D/zhaoyanjun: MainActivity2 进程: com.zhaoyanjun:remote 获取值: value1
5、AIDL 简介
AIDL的语法十分简单,与Java语言基本保持一致,需要记住的规则有以下几点:
1、AIDL文件以 .aidl
为后缀名
2、 AIDL支持的数据类型分为如下几种:
- 八种基本数据类型:
byte
、char
、short
、int
、long
、float
、double
、boolean
String
,CharSequence
- 实现了
Parcelable
接口的数据类型 - List 类型。
List
承载的数据必须是AIDL
支持的类型,或者是其它声明的AIDL
对象 - Map类型。
Map
承载的数据必须是AIDL
支持的类型,或者是其它声明的AIDL
对象
3、AIDL
文件可以分为两类。一类用来声明实现了Parcelable
接口的数据类型,以供其他AIDL
文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值。
3、定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。
- 其中 in 表示数据只能由客户端流向服务端,
- out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。定向Tag具体的使用差别后边会有介绍
4、明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下
6、activity、service 进程间通信 AIDL
创建 IBookAidlInterface.aidl
文件
创建 IBookAidlInterface
完成后,会在 main 目录下,创建 aidl 文件夹,并且会创建同名的包名,如下:
我们把默认的 basicTypes 方法删除,修改如下
interface IBookAidlInterface {String getTitle();void setTitle(String title);
}
下面创建 Service , 并指定进程名字:
<serviceandroid:name=".MyService"android:enabled="true"android:exported="true"android:process=":remote" />
MyService 如下:
class MyService : Service() {private var binder: Binder = object : IBookAidlInterface.Stub() {override fun getTitle(): String {return "aidl->title"}override fun setTitle(title: String?) {Log.d("aidl", "service-setTitle:$title")}}override fun onBind(intent: Intent): IBinder {return binder}override fun onCreate() {super.onCreate()}
}
MainActivity 绑定Service
class MainActivity : AppCompatActivity() {private var iBookAidlInterface: IBookAidlInterface? = nullprivate var serviceConnection: ServiceConnection = object : ServiceConnection {override fun onServiceDisconnected(name: ComponentName?) {}override fun onServiceConnected(name: ComponentName?, service: IBinder?) {iBookAidlInterface = IBookAidlInterface.Stub.asInterface(service)var name = iBookAidlInterface?.titleLog.d("aidl", "getTitle: $name")iBookAidlInterface?.title = "我是一个title"}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)bindService()}/*** 绑定服务*/private fun bindService() {var intent = Intent(this, MyService::class.java)bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)}override fun onDestroy() {super.onDestroy()unbindService(serviceConnection)}
}
运行项目,日志如下:
可以看到,子进程 Service 和 主进程的 Activity 已经可以通信了。
github 地址:https://github.com/zyj1609wz/AndroidMultiProgress
7、AIDL 传递复杂对象
首先创建 Book 类,并且实现 Parcelable
接口。这里要注意,一定要实现 Parcelable
接口,因为只有实现 Parcelable
的复杂对象才能在 AIDL 中传递。
public class Book implements Parcelable {public String title;Book() {}protected Book(Parcel in) {title = in.readString();}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(title);}@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];}};
}
同时在 aidl 目录中定义 Book.aidl
文件,并且声明 parcelable
属性。Book.aidl
文件如下:
package com.yanjun.progress;parcelable Book;
下面我们修改 IBookAidlInterface.aidl
的方法,如下:
interface IBookAidlInterface {String getTitle();void setTitle(String title);Book getBook();void setBook(in Book book);
}
需要注意的是 setBook
方法,一定要声明 Book
对象是 in
属性,表明是 book 对象是从客户端流向服务端。
最后在 Service 里面实现接口就行了,如下:
class MyService : Service() {private var binder: Binder = object : IBookAidlInterface.Stub() {override fun getTitle(): String {return "aidl->title"}override fun setTitle(title: String?) {Log.d("aidl", "service-setTitle:$title")}override fun getBook(): Book {var book = Book()book.title = "书的名字"return book}override fun setBook(book: Book?) {}}override fun onBind(intent: Intent): IBinder ?{return binder}override fun onCreate() {super.onCreate()}
}
demo github 地址:https://github.com/zyj1609wz/AndroidMultiProgress
8、SharedPreferences 跨进程
SharedPreferences
要实现跨进程通信,要遵循文件名字相同的规则。而且是同一个应用,两个进程间。
SharedPreferences
之所以能实现跨进程,是因为SharedPreferences
数据存在SD卡的磁盘中,两个进程共用一个文件。
注意事项:
- 虽然
SharedPreferences
可以实现跨进程,但是Google
官方不建议使用,因为Google
认为多个进程读同一个文件都是不安全的,Android
不保证该模式总是能正确的工作,建议使用ContentProvider
替代多进程之间文件的共享。
额外话题 SharedPreferences 优化:
commit
是把内容同步提交到硬盘的,返回boolean
表明修改是否提交成功apply
先立即把修改提交到内存,然后开启一个异步的线程提交到硬盘,并且如果提交失败,你不会收到任何通知,apply没有返回值 。- 使用了
apply
方式异步写sp
的时候,每次apply()
调用都会新增一个finisher
。在有些系统生命周期事件发生的时候都会去检查已经提交的apply
写操作是否完成,如果没有完成则阻塞主线程,造成ANR
- 当一个文件较大时,首次读取可能会较慢,每次写入也会较慢
- 在不同模块使用多个文件存储的情况下,那么未被使用到的模块,不会被读取进内存
- 当存储的
value
为json
或者html
形式时,由于特殊符号较多,会占用更多的字符
如何解决 ANR :
- 如果处理
SP
的时候,使用commit
方法替代apply
,在保证调用时线程正确处理,并保证同一文件不使用多个线程写入的情况下,不会出现该ANR
。 - 自查是否有一下子修改多个
key-value
且apply
多次的情况,如有,可合并为put
多次但apply
一次
9、广播跨进程
Context.sendBroadcast()
发送的是普通广播,所有订阅者都有机会获得并进行处理
10、ContentProvider跨进程
什么是ContentProvider ?
即 内容提供者,是 Android
四大组件之一
ContentProvider什么作用?
进程间 进行数据交互 & 共享,即跨进程通信
ContentProvider原理
ContentProvider
的底层原理 = Android
中的Binder
机制
ContentProvider优秀文章链接
本来是想总结一下的,但是我发现了一篇写的很好的文章:
建议把文章和评论都看看,很有收获。
Android:关于ContentProvider的知识都在这里了!
Android中使用Contentprovider导致进程被杀死
11、Socket跨进程通信
优点:
- 功能强大,可通过网络传输字节流,支持一对多实时并发通信
缺点:
- 实现细节步骤稍繁琐,不支持直接的RPC
适用场景:
- 网络间的数据交换
12、文件共享跨进程
优点
- 简单易用
缺点:
- 不适用高并发场景,并且无法做到进程间即时通信
适用场景:
- 适用于无关发的情况下,交换简单的数据,对实时性要求不高的场景。
13、Bundle跨进程
优点
- 简单易用
缺点:
- 只能传输Bundle支持的数据类型
适用场景:
- 四大组件间的进程间通信
14、MMKV
MMKV
是国内微信团队开源的高性能 key-value
组件,良好的支持Android
跨进程通信,具体使用方法就自己看文档吧,这里不赘述了。
github: https://github.com/Tencent/MMKV/
中文文档:MMKV中文文档
Android 跨进程通信大总结相关推荐
- 【朝花夕拾】Android跨进程通信总结篇
前言 原文:https://www.cnblogs.com/andy-songwei/p/10256379.html 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一. ...
- 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10256379.html],谢谢! 只要是面试高级工程师岗位,Android跨进程通信就是最受面 ...
- 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇...
前言 原文:https://www.cnblogs.com/andy-songwei/p/10256379.html 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一. ...
- Android跨进程通信Binder机制与AIDL实例
文章目录 进程通信 1.1 进程空间划分 1.2 跨进程通信IPC 1.3 Linux跨进程通信 1.4 Android进程通信 Binder跨进程通信 2.1 Binder简介 2.2 Binder ...
- Android 跨进程通信(一)
Android 跨进程通信 Android 本身提供一四种方式进行实现跨进程通信,他们也分别是Android的四大组件.分别是:Activity,Content Provider,Broadcast和 ...
- Android - 跨进程通信(IPC) 另一种便捷实现 详解
文章目录 1. 写在前面 2. 跨进程通信的实现 3. 扩展思考 4. 参考资料 1. 写在前面 看到此图有何感想,这是另一种便捷的实现方式,我们先来看看其它的几种方式. Android 进程间通信 ...
- 【Binder】Android 跨进程通信原理解析
前言 在Android开发的过程中,用到跨进程通信的地方非常非常多,我们所使用的Activity.Service等组件都需要和AMS进行跨进程通信,而这种跨进程的通信都是由Binder完成的. 甚至一 ...
- Android跨进程通信
一 多进程之间的通信 由于不同进程所拥有的地址是两块不同的地址空间,所以不能直接通过共享内存共享数据了. Linux常用跨进程通信方式:管道,信号量,共享内存,socket Android常用跨进程通 ...
- 使用AIDL+动态代理+运行时注解+反射 反手撸一套Android跨进程通信框架
IPC 前言 跨进程通信方式 跨进程通信框架 涉及到的技术 使用Request-Response思想 IPCRequest IPCResponse RemoteService 服务端 客户端 附带 项 ...
最新文章
- 图像解码之一——使用libjpeg解码jpeg图片
- 【评估价格】采购申请中的价格
- 为jquery.AutoComplete添加触发事件
- Redis入门到入土教程_2 远程连接redis
- hihoCoder - 1079 - 离散化 (线段树 + 离散化)
- 哈佛结构 Linux,哈佛结构与冯诺依曼结构区别
- Quectel BC95-CNV 多频段、高性能、低功耗 LTE Cat NB2无线通信模块[移远通信]
- 怎么使用QQ音乐api搭建个人音乐站点
- WPS永久关闭热点、云服务、初始登陆界面
- 数据仓库系列7-ETL 子系统与技术
- 【零基础】speech driven animation中文安装使用指南
- 华为HCNA独家视频课程
- 一文看透 Kotlin 协程本质
- 鸟哥的linux私房菜_linux磁盘与文件系统管理
- MySQL数据库实操教程(25)——权限管理
- 无线通信模块定点传输-点对点的具体传输应用
- 地图不是领地尼克·格里尔的采访
- Excel VBA高级编程 - 根据关键字自动搜索,自动生成下拉菜单
- TM1814 WRGB的一种驱动方法:UART
- cass实体编码列表