进程间通讯:Binder: Binder原理剖析

  • Post author:
  • Post category:其他


1:Binder原理解析

1: 这是一种比startService更复杂的启动方式,同时使用这种方式启动的service也能完成更多的事情,

2: 比如其他组件可向其发送请求,接受来自它的响应,甚至通过它来进行IPC等等。我们通常将绑定它的组件称为客户端,而称它为服务端。

3:如果要创建一个支持绑定的service,我们必须要重写它的onBind()方法。这个方法会返回一个IBinder对象,它是客户端用来和服务器进行交互的接口。

而要得到IBinder接口,我们通常有三种方式:继承Binder类,使用Messenger类,使用AIDL。

上面概念如此复杂,下来跟着我来一步一步解析Binde诞生过程。

举个例子:



使用Binder实现一个客户端连接服务端查询学生成绩的例子。


1.服务端提供查询服务

public class GradeService extends Service {
    public static final int REQUEST_CODE=1000;
    private final Binder mBinder = new Binder() {
        @Override
        protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
            if (code == REQUEST_CODE) {

                // 1 先匹配客户端的请求码,然后从data读出数据
                String name = data.readString();

                // 根据姓名查询学生成绩并将成绩写入到返回数据
                int studentGrade = getStudentGrade(name);
                if (reply != null)

                    // 2. 从reply向客户端写返回值,这时唤醒了客户端。
                    reply.writeInt(studentGrade);

                 // 3. 处理完成
                return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
        // 根据姓名查询学生成绩
        public int getStudentGrade(String name) {         
            return StudentMap.getStudentGrade(name);
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

<service
    android:name="com.zhpan.sample.binder.server.GradeService"
    android:process=":server">
    <intent-filter>
        <action android:name="android.intent.action.server.gradeservice" />
    </intent-filter>
</service>

2.客户端连接服务查询成绩

public class BinderActivity extends AppCompatActivity {
    // 远程服务的Binder代理
    private IBinder mRemoteBinder;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 获取远程服务的Binder代理
            mRemoteBinder = iBinder;
       
             // 1:从对象池拿到可复用的对象(享元模式)
             Parcel data = Parcel.obtain();
             Parcel reply = Parcel.obtain();
             int grade = 0;

             // 2. 往 data里面写数据,作为请求参数
             data.writeString(name);
             try {
                 if (mRemoteBinder == null) {
                throw new IllegalStateException("Need Bind Remote Server...");
              }

            // 3. 拿到了服务端的IBinder句柄,调用 transact ,并约定请求码,其中第四个参数
            flag = 0 表示同步调用,1 表示表示异步调用
            mRemoteBinder.transact(REQUEST_CODE, data, reply, 0);
            
            //4 从服务端已经获取到内容了,直接从 relpy中读取
            grade = reply.readInt();
            } catch (RemoteException e) {
            e.printStackTrace();
            }
            return grade;

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mRemoteBinder = null;
        }
    };



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder);
        // 绑定服务
        findViewById(R.id.btn_bind_service).setOnClickListener(view -> bindGradeService());

    }
    // 绑定远程服务
    private void bindGradeService() {
        String action = "android.intent.action.server.gradeservice";
        Intent intent = new Intent(action);
        intent.setPackage(getPackageName());
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }

2:Binder原理剖析2


图解 | Binder浅析(一)

3:Binder原理图

3.1 Binder总结

1:通过这个例子,我们可以看出,Binder机制使用了

Parcel来序列化数据

,客户端在主线程调用了

transact来请求

(Parcel data传参),服务端在

Binder线程

调用

onTransact来响应

(Parcel reply回传结果)。

2: 由于我们的flags传入的是

0

同步调用,可以试着在服务端onTransact里sleep几秒,会发现客户端需要几秒后才能打印出返回值。所以如果服务端需要进行耗时操作,客户端则需要在子线程里进行binder调用。

3:默认情况下,binder传递数据是同步的,

transact(int code, Parcel data, Parcel reply, int flags)

你可以定义oneway关键字来实现异步

mRemote.transact(int code, Parcel data, Parcel reply,  android.os.IBinder.FLAG_ONEWAY);



版权声明:本文为u013620306原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。