用大白话解释 Android 进程间通信(IPC)的方式
一句话总结:
进程间通信就像"不同办公室之间传纸条",Android 提供了多种传纸条的方式,各有优缺点,用对场景是关键!
1. Intent(最基础的方式)
-
场景:启动其他应用的页面(Activity)或服务(Service)。
-
原理:通过系统"邮局"传递简单数据。
-
示例:
kotlin// 发送方(App A) val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com")) startActivity(intent) // 接收方(App B 的 Activity) override fun onCreate(savedInstanceState: Bundle?) { val data = intent?.data // 获取传递的数据 }
-
优点:简单易用,系统级支持。
-
缺点:只能传简单数据,不能跨进程频繁通信。
2. Bundle(Intent 的扩展包)
-
场景:在 Intent 基础上传递复杂数据(对象、文件描述符)。
-
原理:把数据打包成"包裹",通过 Intent 传递。
-
示例:
scssval bundle = Bundle().apply { putString("key", "value") putParcelable("user", User("Alice")) } intent.putExtras(bundle)
-
限制 :传输的对象必须实现
Parcelable
或Serializable
。
3. Binder(Android 的 IPC 核心)
-
场景:跨进程调用服务(如系统服务、自定义后台服务)。
-
原理:通过"代理模式"实现远程方法调用(类似打电话)。
-
核心组件:
- AIDL(Android Interface Definition Language) :定义接口,自动生成 Binder 代码。
- Service:实现接口,处理远程调用。
-
示例:
kotlin// AIDL 文件(IRemoteService.aidl) interface IRemoteService { int add(int a, int b); } // 服务端实现 class RemoteService : Service() { private val binder = object : IRemoteService.Stub() { override fun add(a: Int, b: Int) = a + b } override fun onBind(intent: Intent) = binder } // 客户端调用 val serviceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { val remoteService = IRemoteService.Stub.asInterface(service) val result = remoteService.add(1, 2) // 跨进程调用 } } bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
-
优点:高效,支持复杂交互。
-
缺点:代码较复杂,需处理多线程和异常。
4. Messenger(基于 Binder 的简化版)
-
场景:跨进程发送消息(串行处理,适合简单通信)。
-
原理:通过 Handler 传递 Message,底层基于 Binder。
-
示例:
kotlin// 服务端 class MessengerService : Service() { private val handler = object : Handler(Looper.getMainLooper()) { override fun handleMessage(msg: Message) { // 处理客户端消息 val reply = Message.obtain() reply.what = 1 reply.arg1 = msg.arg1 + msg.arg2 msg.replyTo.send(reply) } } private val messenger = Messenger(handler) override fun onBind(intent: Intent) = messenger.binder } // 客户端 val clientMessenger = Messenger(Handler(Looper.getMainLooper())) val message = Message.obtain().apply { what = 1 arg1 = 10 arg2 = 20 replyTo = clientMessenger } serviceMessenger.send(message)
-
优点:比直接 Binder 简单,适合单向或简单双向通信。
-
缺点:不能并行处理消息。
5. ContentProvider(数据共享的"公共仓库")
-
场景:跨进程共享结构化数据(如通讯录、媒体库)。
-
原理 :通过 URI 暴露数据接口,其他应用通过
ContentResolver
访问。 -
示例:
kotlin// 定义 ContentProvider class MyProvider : ContentProvider() { override fun query(uri: Uri, ...): Cursor { // 根据 URI 查询数据 return database.query(...) } } // 客户端查询 val cursor = contentResolver.query( Uri.parse("content://com.example.provider/data"), null, null, null, null )
-
优点:标准化数据访问,支持权限控制。
-
缺点:适合结构化数据,不适合高频或复杂操作。
6. 文件 & SharedPreferences(原始方式)
-
场景:跨进程读写同一文件或配置。
-
原理:通过文件系统共享数据(需处理并发)。
-
示例:
scss// 写入文件 File("/sdcard/shared.txt").writeText("Hello") // 读取文件 val content = File("/sdcard/shared.txt").readText()
-
优点:简单,无需复杂配置。
-
缺点:效率低,并发易出错,安全性差。
7. Socket(网络通信)
-
场景:跨设备或本机进程间网络通信。
-
原理:通过 TCP/IP 或本地 Socket 传输数据。
-
示例:
scss// 服务端 val serverSocket = ServerSocket(8080) val socket = serverSocket.accept() val input = socket.getInputStream().bufferedReader().readLine() // 客户端 val socket = Socket("localhost", 8080) socket.getOutputStream().bufferedWriter().write("Hello")
-
优点:跨网络通用,灵活性高。
-
缺点:实现复杂,性能开销大。
总结:如何选择 IPC 方式?
场景 | 推荐方式 |
---|---|
启动其他应用页面 | Intent |
跨进程方法调用(复杂接口) | Binder/AIDL |
简单消息传递(单向/双向) | Messenger |
结构化数据共享(如数据库) | ContentProvider |
临时数据共享(非高频) | 文件/SharedPreferences |
跨设备或网络通信 | Socket |
注意事项(避坑指南)
- 权限控制 :跨进程访问需声明权限(如 ContentProvider 的
android:permission
)。 - 性能优化:高频通信优先选 Binder,避免用文件或 Socket。
- 安全性 :防止恶意应用窃取数据(如 Intent 添加
FLAG_GRANT_READ_URI_PERMISSION
)。 - 版本兼容:不同 Android 版本对 IPC 的限制不同(如后台 Service 限制)。
口诀 :
"Intent 传页 Messenger 信,
Binder 复杂 AIDL 定,
文件共享效率低,ContentProvider 管数据,
Socket 跨网也能行,选对方式最要紧!"