专栏名称: 黎伟杰
Android开发工程师
目录
相关文章推荐
指尖新闻沈阳晚报  ·  注意!女子按摩后确诊急性脑梗死!曾有明星因此 ... ·  昨天  
三亚广播电视台  ·  春雷响,万物长! ·  昨天  
古典文献学微刊  ·  期刊 | ... ·  2 天前  
楚天交通广播  ·  女子按摩肩颈后被确诊急性脑梗死,进了ICU! ... ·  2 天前  
海峡都市报闽南新闻  ·  3年长胖40斤,健康亮红灯!他狠下心减重,半 ... ·  2 天前  
51好读  ›  专栏  ›  黎伟杰

Binder总结篇2-Binder使用

黎伟杰  · 掘金  ·  · 2018-08-18 17:53

正文

阅读 8

Binder总结篇2-Binder使用

Binder总结篇2-Binder使用

在上一篇文章 Binder总结篇1-Binder原理 中,我们大概理解了Binder的运行原理,那么我们在什么样子的应用场景下会使用到Binder呢?

就我个人而言,是在IM系统开发当中使用到多进程开发,也就需要Binder来进行通信了,本文是编写实际的例子的,涉及到的点有:

  1. AIDL

包括支持的数据类型,定义以及使用等

  1. Service

包括一些启动,数据获取以及数据回传等。

本文的demo地址是: AndroidBinderSample

AIDL

关于AIDL的详细描述,可以看官网 Android 接口定义语言 (AIDL)

他是Android的接口定义语言,用来具体实现Binder通信过程的数据传递,格式跟java的接口代码的编写差不多。 他是使用.aidl文件结尾,存放在man文件夹下的aidl文件夹下,当然你可以通过在gradle中配置 aidl.srcDirs 来指定。

AIDL支持的数据类型

  1. Java的基本类型,也包括String类型和CharSequence类型
  2. List 和Map,其中List和Map中的元素必须是AIDL支持的数据类型,而且在Server端必须使用ArrayList或者是HashMap来接收。
  3. 其他的AIDL生成的接口
  4. 实现了Parcelable接口的实体,可以看 详细介绍Android中Parcelable的原理和使用方法

AIDL文件,总得来说,AIDL分为两类文件,一种是接口类型,就是需要被调用被实现的。一种是声明Parcelable数据,作用就是把对应的Java实现了Parcelable接口的类映射到AIDL中,然后被AIDL的接口文件引用,需要注意的是这个AIDL文件的包名需要与Java实现Parcelable文件对应的包名一致。 例如: 我们声明了一个JavaDomain,在包 app.androidbinder.domain 下,大致如下

package app.androidbinder.domain;
import android.os.Parcel;
import android.os.Parcelable;
/**
 * 作者:黎伟杰 on 2018/8/13.
 * 邮箱:[email protected]
 * description:
 * update by:
 * update day:
 *
 * @author liweijie
 */
public class UserInfo implements Parcelable {
      //省略代码
    public UserInfo() {
    }
    protected UserInfo(Parcel in) {
          //省略代码
    }
    public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {
        @Override
        public UserInfo createFromParcel(Parcel in) {
            return new UserInfo(in);
        }
        @Override
        public UserInfo[] newArray(int size) {
            return new UserInfo[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //省略代码
    }
    public void readFromParcel(Parcel in) {
        //省略代码
    }
}
复制代码

然后在AIDL文件下也需要建立对应的包名,然后编写UserInfo.aidl,如下:

package app.androidbinder.domain;
/**
 * 作者:黎伟杰 on 2018/8/14.
 * 邮箱:[email protected]
 * description:
 * update by:
 * update day:
 *
 * @author liweijie
 */
parcelable UserInfo;
复制代码

这样子,在别的AIDL中就可以引用这个 UserInfo 了。 定义接口类型的AIDL如下:

// UserService.aidl
package app.androidbinder;
import java.util.List;
import app.androidbinder.domain.UserInfo;
// Declare any non-default types here with import statements
interface UserService {
    String getUserName(int userId);
    void saveUser(in UserInfo param);
    UserInfo getUserInfo(int userId);
    List<UserInfo> queryUser();
    //for in out inout
    UserInfo handleIn(in UserInfo info);
    UserInfo handleOu(out UserInfo info);
    UserInfo handleInOut(inout UserInfo info);
}
复制代码

这就是两种AIDL文件类型以及对应的大致编写。

in、out、inout

在官方文档中支出,所有的非原语参数需要指示数据的方向标记,可以是in、out、inout。默认的原语是in,不能是其他流向。 这里指定的非原语是指:除了Java的基本类型外的其他参数,也就是对象。我们在AIDL使用的时候需要知道这个参数的流向。 那什么是数据的方向标记呢? 首先,数据的方向标记是针对客户端中的那个传入的方法参数而言。数据流向的标识符不能使用在返回参数上,只能使用在方法参数上面。

  1. in:他表示的是这个参数只能从客户端流向服务端,比如客户端传递了一个User对象给服务端,服务端会收到一个完整的User对象,然后假如在服务端对这个对象进行操作,那么这个改变是不会反映到客户端的,这个流向也就是只能从客户端到服务端。
  2. out:他表示,当客户端传递参数到服务端的时候,服务端将会收到一个空的对象,假如服务端对该对象进行操作,将会反映到客户端。比如,客户端传递一个User对象到服务端,服务端接收到的是一个空的User对象(不是null,只是有点像new一个User对象)。当服务端对这个User对象进行改变的时候,他的值变化将会反映到客户端。
  3. inout,它具有这二者的功能,也就是客户端传递对象到服务端,可以接收到完整的对象,同时服务端改变对象,也会反映到客户端。 总结来说,in类似于传值,out类似于传引用,只是out的引用值到了服务端为空,inout则具有二者的功能,默认的是in。

Service

多进程之间的通信离不开的是Service,Android四大组件之一,这里不过多的赘述,只是需要知道我们在多进程通信当中,服务端最少提供一个 Service 来,在 onBind() 方法中返回实现AIDL接口的 IBinder 对象。然后客户端通过 bindService() 来连接,通过在 ServiceConnection onServiceConnected 方法,通过调用AIDL 生成的文件中的 Stub asInterface() 来在客户端获取服务实例,继而调用服务端的方法。需要注意,在跨app的进程调用中,对外暴露的 Service 需要在清单文件中把 android:exported 设置为 true 。一般而言,我们还会配置一些fillter来进行过滤。 关于如何使用Service以及他的一些生命周期,一些方法区别(比如startService和bindService)请自己另外查阅文档,这里就不描述了。以下是本文Demo中的实例,使用的还是上面的AIDL,使用之前确保成功编译出对应的aidl生成文件:

服务端的Service

package app.androidbinder2.services;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import app.androidbinder.UserService;
import app.androidbinder.domain.UserInfo;
/**
 * 作者:黎伟杰 on 2018/8/12.
 * 邮箱:[email protected]
 * description:
 * update by:
 * update day:
 *
 * @author liweijie
 */
public class App2Service extends Service {
    /**
     * 模拟一些测试数据
     */
    private List<UserInfo> data = new ArrayList<>();
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        data.clear();
        data.add(new UserInfo(1, "A", 20));
        data.add(new UserInfo(2, "B", 30));
        data.add(new UserInfo(3, "C", 40));
        data.add(new UserInfo(4, "D", 50));
        return userService;
    }
    private Binder userService = new UserService.Stub() {
        @Override
        public String getUserName(int userId) throws RemoteException {
            for (UserInfo item : data) {
                if (item.getUserId() == userId) {
                    return item.getUserName();
                }
            }
            return null;
        }
        @Override
        public void saveUser(UserInfo param) throws RemoteException {
            data.add(param);
        }
        @Override
        public UserInfo getUserInfo(int userId) throws RemoteException {
            for (UserInfo item : data) {
                if (item.getUserId() == userId) {
                    return item;
                }
            }
            return null;
        }
        @Override
        public List<UserInfo> queryUser() throws RemoteException {
            return data;
        }
        @Override
        public UserInfo handleIn(UserInfo info) throws RemoteException {
            info.setUserName("嘿嘿嘿");
            return info;
        }
        @Override
        public UserInfo handleOu(UserInfo info) throws RemoteException {
            if (info == null) {
                Log.e("App2Service", "UserInfi server is null");
                info = new UserInfo();
            }
            info.setUserName("嘻嘻嘻");
            return info;
        }
        @Override
        public UserInfo handleInOut(UserInfo info) throws RemoteException {
            info.setUserName("哈哈哈");
            return info;
        }
    };
}
复制代码

清单文件的配置是:

     <service
            android:name=".services.App2Service"






请到「今天看啥」查看全文