Binder通信应用

时间:2023-01-05 01:14:37


介绍

  • [x] Binder由四部分组成:Binder客户端、Binder服务端、Binder驱动、服务登记查询模块。
  • Binder客户端是想要使用服务的进程。
  • Binder服务端是实际提供服务的进程。
  • Binder驱动:
1.客户端先通过Binder拿到一个服务端进程中的一个对象的引用,
2.通过这个引用,直接调用对象的方法获取结果。
3.在这个引用对象执行方法时,它是先将客户端方法调用的请求传给Binder驱动;
4.然后Binder驱动再将客户端请求传给服务端进程;
5.服务端进程收到请求后,调用服务端“真正”的对象来执行所调用的方法;得出结果后,将结果发给Binder驱动;
6.Binder驱动再将结果发给我们的客户端;
7.最终,我们在客户端进程的调用就有了返回值。
8.Binder驱动,相当于一个中转者的角色。通过这个中转者的帮忙,我们就可以调用其它进程中的对象。
  • Service Manager(服务登记查询模块)
1.我们调用其它进程里面的对象时,首先要获取这个对象。这个对象其实代表了另外一个进程能给我们提供什么样的服务(再直接一点,就是:对象中有哪些方法可以让客户端进程调用)。
 2.首先服务端进程要在某个地方注册登记一下,告诉系统我有个对象可以公开给其它进程来提供服务。当客户端进程需要这个服务时,就去这个登记的地方通过查询来找到这个对象

Binder工作流程

  • 假设:客户端的程序Client运行在进程A中,服务端的程序Server运行在进程B中。
  • 由于进程的隔离性,Client不能读写Server中的内容,但内核可以,而Binder驱动就是运行在内核态,因此Binder驱动帮我们进行请求的中转。
  • 有了Binder驱动,Client和Server之间就可以打交道了,但是为了实现功能的单一性,我们为Client和Server分别设置一个代理:Client的代理Proxy和Server的代理Stub。这样,由进程A中的Proxy和进程B中的Stub通过Binder驱动进行数据交流,Server和Client直接调用Stub和Proxy的接口返回数据即可。
  • 此时,Client直接调用Proxy这个聚合了Binder的类,我们可以使用一系列的Manager来屏蔽掉Binder的实现细节,Client直接调用Manager中的方法获取数据,这样做的好处是Client不需要知道Binder具体怎么工作。
  • Client想要获得的服务多种多样,那么它是怎么获取Proxy或Manager的呢?答案是通过Service Manager进程来获取的。Service Manager总是第一个启动的服务,其他服务端进程启动后,可以在Service Manager中注册,这样Client就可以通过Service Manager来获取服务器的服务列表,进而选择具体调用的服务器进程方法。

AIDL通信实例

  • ①两个进程的activity
<activity
            android:name=".ServerActivity"
            android:process=":remote" />
        <activity android:name=".ClientActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
  • ②创建aidl文件和用于客户端与服务端通信的方法
/**
 * @Author yangtianfu
 * @Data 2021/4/1 18:01
 * @Des ②创建aidl文件和用于客户端与服务端通信的方法
  */
interface IMyAidlInterface {
   void setName(String name);
   String getName();
}

Binder通信应用

  • ③AIDL文件声明完,activity等文件并不能调用到IInfManager接口,需要在app的build.gradle文件中的android{}中添加
sourceSets{
        main{
            java.srcDirs = ['src/main/java', 'src/main/aidl']
        }
    }
  • ④Service中创建Binder对象,onBind方法中返回这个对象,Binder对象中具体实现了IMyAidlInterface接口中的方法。Service记得在AndroidManifest.xml中注册
<service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
package com.example.binderapp

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.os.RemoteException

/**
 * @Author yangtianfu
 * @Data 2021/4/1 18:09
 * @Des ④Service中创建Binder对象,
 * 在onBind方法中返回这个对象,Binder对象中具体实现了IMyAidlInterface接口中的方法。Service记得在AndroidManifest.xml中注册
 */
class MyService : Service() {
    private var name: String? = ""

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        name = intent?.getStringExtra("name")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }

    private val binder: Binder = object : IMyAidlInterface.Stub() {

        @Throws(RemoteException::class)
        override fun setName(mName: String) {
            name = mName
        }

        @Throws(RemoteException::class)
        override fun getName(): String {
            return name?:""
        }

    }
}
  • ⑤ 服务端
package com.example.binderapp

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity

class ServerActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_server)
        val intent = Intent(this@ServerActivity,MyService::class.java)
        intent.putExtra("name","BlissYang")
        startService(intent)
    }

    fun jumpClient(view: View) {
        startActivity(Intent(this@ServerActivity, ClientActivity::class.java))
    }
}
  • ⑥客户端
package com.example.binderapp

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import androidx.appcompat.app.AppCompatActivity


class ClientActivity : AppCompatActivity() {

    private var iMyAidlInterface: IMyAidlInterface? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val intent = Intent(this@ClientActivity,MyService::class.java)
        bindService(intent,connection, Context.BIND_AUTO_CREATE)
//        Thread.sleep(3_000L)
//        iMyAidlInterface?.name = "客户端消息"
    }

    private val connection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service)
            try {
                Log.i("ClientActivity", "服务端数据:" + iMyAidlInterface?.name)
                iMyAidlInterface?.name = "YangTianfu"
                Log.i("ClientActivity", "next:" + iMyAidlInterface?.name)
            } catch (e: RemoteException) {
            }
        }

        override fun onServiceDisconnected(name: ComponentName) {
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        unbindService(connection)
    }
}