Android进程间通信之bindService篇

背景概述

在Android中binder是一种非常重要的进程间通信方式。基于binder实现的进程间通信形态非常多,其中Android的四大组件之一Service,可以用来和binder机制结合,来实现跨进程通信。这种方式就是bindservice,在bindservice这个场景里面,Service作为一个服务端,给调用端也就是client端提供接口。这种方式一般用于Java端和Java端的跨进程通信。下面来详细讲解一下这种实现方式。

Service的创建

首先,我们需要创建一个service,这个service是用来给client端提供接口的。创建service的方式有三种:

扩展binder类

这种方式是当服务端和客户端在同一个进程时使用。因此,这种方式并不具备跨进程的能力,本文就不详细讲述了。

使用Messenger

这种方式能够实现跨进程通信。主要特点是,它将请求放入一个队列中,服务端不需要进行线程安全设计。这种方式其实在项目开发中使用的并不多。本文也不详细讲述了。

备注:
关于上述两种方式具体可以参考:developer.android.com/guide/compo…

使用AIDL

AIDL是Android提供的一种方便让开发者基于binder来实现跨进程通信的一种工具。它的特点是支持客户端同时并发访问,所以如果你的服务设计为AIDL的方式,那么你需要考虑线程安全的设计。下面来详细说下这种方式:

创建.aidl文件

.aidl文件需要开发者自己按照语法规则来定义。提供服务的服务端和绑定服务的客户端都需要包含.aidl源码文件。一般来说会定义两个aidl文件,一个是给client调用service提供接口定义,另外一个是给service回调client提供接口定义。

实现AIDL中定义的接口

AIDL定义的接口,必须在service端给出每个接口的具体实现。

向client端公开接口

将实现了AIDL接口的实例,通过onBind()接口返回给client端,这样client端才能通过这个实例调用AIDL的接口实现。

备注:
具体实现代码参考:client端源码 github.com/jiantengfei… service端源码 github.com/jiantengfei…
相关文章参考:developer.android.com/guide/compo…

使用AIDL的技术要点

通过IPC调用传递objects

在IPC调用中,需要传递函数型参给对端。在AIDL中,支持以下数据类型的传递:
Java语言中的原语类型(int、long、char、boolean等)
String、CharSequence、List(对端的接收数据是ArrayList)、Map(对端的接收数据是HashMap)
另外还支持自定义对象的IPC传输,但是开发者必须自己实现自定义对象的序列化。在AIDL中是将自定义对象实现Parcelable接口,并给出接口实现,来完成对象的序列化的。
在Android 10以上的版本,可以直接在AIDL中定义Parcelable对象。AIDL工具在编译时可以帮助开发者自动生成对应的对象的序列化代码。参考如下:

package android.graphics;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect {
    int left;
    int top;
    int right;
    int bottom;
} 

如果想要自己来实现的话,首先新增一个Rect.aidl文件

package android.graphics;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect; 

再定义Rect这个类的具体实现:

import android.os.Parcel;
import android.os.Parcelable;

public final class Rect implements Parcelable {
    public int left;
    public int top;
    public int right;
    public int bottom;

    public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
        public Rect createFromParcel(Parcel in) {
            return new Rect(in);
        }

        public Rect[] newArray(int size) {
            return new Rect[size];
        }
    };

    public Rect() {
    }

    private Rect(Parcel in) {
        readFromParcel(in);
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(left);
        out.writeInt(top);
        out.writeInt(right);
        out.writeInt(bottom);
    }

    public void readFromParcel(Parcel in) {
        left = in.readInt();
        top = in.readInt();
        right = in.readInt();
        bottom = in.readInt();
    }

    public int describeContents() {
        return 0;
    }
} 

方法中带有Bundle类型参数

// IRectInsideBundle.aidl
package com.example.android;

/** Example service interface */
interface IRectInsideBundle {
    /** Rect parcelable is stored in the bundle with key "rect" */
    void saveRect(in Bundle bundle);
} 

在service端解析Bundle之前,需要显示在Bundle中setClassLoader。

private final IRectInsideBundle.Stub binder = new IRectInsideBundle.Stub() {
    public void saveRect(Bundle bundle){
        bundle.setClassLoader(getClass().getClassLoader());
        Rect rect = bundle.getParcelable("rect");
        process(rect); // Do more with the parcelable.
    }
}; 

总结

本文主要介绍了Android中,使用binder和binderservice这种方式,来实现Java端和Java端跨进程通信的方式。并简单介绍了下使用AIDL工具的关键技术点。

最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。

小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,需要一份小编整理出来的学习资料的关注我主页或者点击扫描下方二维码免费领取~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值