Android跨进程

397 阅读3分钟

Android跨进程方式

  • Bundle

  • ContentProvider

  • Socket

  • Messager

  • AIDL

Bundle

  1. Android开发中,Bundle 无处不在,不管是启动Activity、Service或者发送Broadcast,都会用到。Android可以通过设置 android:process 设置Activity 或者Service所在的进程,因此Android在设计Bundle 的时候就支持跨进程

    Uri uri = Uri.parse("smsto:10086");
    Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
    Bundle bundle = new Bundle();
    bundle.putString("sms_body", "SMS Text");
    intent.putExtras(bundle);
    //  intent.putExtra("sms_body", "SMS Text");
    startActivity(intent);
    

ContentProvider

  1. 通过继承 ContentProvider ,并实现ContentProvider 的增删改查等方法,实现与其他应用共享数据

文件共享

  1. 通过共享文件,将共享数据写到文件,然后其他程序通过读取文件,就可以实现数据的共享。

Messenger

  1. 服务端定义 Messenger,在 onBind()方法返回

    class MessengerService : Service() {
       var serviceHandler = object : Handler(Looper.getMainLooper()) {
           override fun handleMessage(msg: Message) {
               super.handleMessage(msg)
               when (msg.what) {
                   0x110 -> {
                       LogUtils.d("收到了客户端消息")
                       msg.replyTo.send(Message().apply {
                           what = 0x110
                       })
                   }
               }
    
           }
       }
       var messenger = Messenger(serviceHandler)
    
       override fun onBind(intent: Intent?): IBinder? {
    
           return messenger.binder
       }
    }
    
  2. 客户端绑定服务,发送消息时Message.replyTo 设置成客户端 Messenger

     var handler = object : Handler(Looper.getMainLooper()) {
           override fun handleMessage(msg: Message) {
               super.handleMessage(msg)
               when (msg.what) {
                   0x110 -> {
                       LogUtils.d("收到了服务端0x110消息的回复")
                   }
               }
           }
       }
     var clientMessenger = Messenger(handler)
     var conn = object : ServiceConnection {
               override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                   var messenger = Messenger(service)
                   messenger.send(Message().apply {
                       what = 0x110
                       replyTo = clientMessenger
                   })
    
               }
    
               override fun onServiceDisconnected(name: ComponentName?) {
    
               }
           }
           var intent = Intent().apply {
               action = "com.zjp.messengerservice"
               setPackage("com.zjp.androidacrossprocessesservice")
           }
      var result = bindService(intent, conn, Context.BIND_AUTO_CREATE)
    
  3. 服务端收到消息,通过Message.replyTo 给客户端发送消息

    var serviceHandler = object : Handler(Looper.getMainLooper()) {
           override fun handleMessage(msg: Message) {
               super.handleMessage(msg)
               when (msg.what) {
                   0x110 -> {
                       LogUtils.d("收到了客户端消息")
                       msg.replyTo.send(Message().apply {
                           what = 0x110
                       })
                   }
               }
    
           }
       }
    var messenger = Messenger(serviceHandler)
    

AIDL

  1. 创建AIDL文件:

    通过Android Studio File -> New ->AIDL ->AIDL File ,就可以创建一个AIDL文件。然后Rebuild Project ,Android Studio 就会自动在 build -> generated -> buildType -> out 目录下生成对应的 .java文件,里面就包含了后期我们用到的Stub类。

  2. 实现Stub 接口:

    var stub = object : Stub() {
           override fun basicType(
               anInt: Int,
               aLong: Long,
               aBoolean: Boolean,
               aFloat: Float,
               aDouble: Double,
               aString: String?
           ): String {
    
               return "this data is from service"
           }
       }
    
  3. onBind 方法返回 stub,向客户端公开接口:

    override fun onBind(intent: Intent?): IBinder? {
    
           return stub.asBinder()
       }
    

    现在,binderStub 类的一个实例(一个 Binder),其定义了服务的远程过程调用 (RPC) 接口。在下一步中,我们会向客户端公开此实例,以便客户端能与服务进行交互。

    • 默认情况下,RPC 调用是同步调用。如果您知道服务完成请求的时间不止几毫秒,则不应从 Activity 的主线程调用该服务,因为这可能会使应用挂起(Android 可能会显示“Application is Not Responding”对话框)— 通常,您应从客户端内的单独线程调用服务

    • 您引发的任何异常都不会回传给调用方。

    AIDL 支持一下数据类型

    • Java基本数据类型 byte char short int long float double boolean

    • String

    • CharSequence

    • List List里面所有数据必须实现 Parcelable

    • Map Map里面所有数据必须实现 Parcelable

  4. 复制服务端 aidl 文件夹到 客服端对应位置,客户端在 onServiceConnected() 回调中YourServiceInterface*.Stub.asInterface(service),以将返回的参数转换成YourServiceInterface类型。

  5.  var conn = object : ServiceConnection {
                override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                    var stub = IMyAidlInterface.Stub.asInterface(service)
                    var result = stub.basicTypes(1, 1, false, 1.0f, 1.0, "测试")
     
                }
     
                override fun onServiceDisconnected(name: ComponentName?) {
     
                }
     }
    

最后

  • 文件共享:适用于 实时性要求不高,并发场景不多的情况,用法简单通用

  • Bundle: 适用于Android四大组件之间

  • ContentProvider: 适用于为其他客户端提供数据,不涉及双向通信

  • AIDL: 适用于大量复杂数据,有实时双向数据通讯

  • Messenger: AIDL的简化版本,适用于数据简单,数据交换不是那么频繁