Android 项目中 Protobuf 的使用详解

最近项目中有用到传输数据,用到了Protobuf, 在此总结一下如何使用Protobuf

1. 什么是protobuf

Google 官网的解释是: Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data 。

翻译过来大概就是:Protocol Buffers(也称protobuf)是google旗下一款独立于开发语言,独立于平台的可扩展的结构化数据序列机制。

简单来说,就是像json、xml这种用来传输数据的一种数据交互协议。不过,相比与json、xml,protobuf采用了二进制序列化 从而更加轻便与高效,体积小3倍,处理速度快8~20倍,更适合对传输效率敏感的项目中,而且也是跨平台,支持多种编程语言C,C++,java, python, JavaScript, php, ruby等;

2. 使用protobuf 需要准备的工作

在一个项目中要使用protobuf 需要准备两项内容:

一个是protobuf的jar包,这个是需要加入到我们项目中lib文件夹下的

另外一个就是protobuf根据我们结构化的数据生成的java文件, 这个也是要加到项目中

一 ) build protobufjar

由于ProtoBuf的官方下载包并不包含jar文件,需要自己进行编译,可以选择Linux下编译,也可以选择windows

我这里选择了windows的方法,有兴趣的同学可以试试Linux环境下的

需要准备的东西:JDK,maven,protobuf.exe,protobuf的源文件

1)JDK  下载安装

下载地址: https://www.orace.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html   

 选择 jdk-8u211-windows-x64.exe

 下载速度真的是醉了,需要安装包的可以找我,直接安装完 配置环境变量即可 (一般Android开发人员都有安装这个,安装过的可以选择忽略这步)

2)Maven 下载安装

①   下载地址     https://maven.apache.org/download.cgi

       将下载的压缩包解压到某个目录下

       我这里下载到了  D:\Program Files\apache-maven-3.6.1

②    添加系统环境变量 path

③   配置Maven本地仓库

      找到D:\Program Files\apache-maven-3.6.1\conf\settings.xml

      添加  <localRepository>D:/Program Files/apache-maven-3.6.1/repo</localRepository>

      并添加repo 这个文件夹,以后maven需要从仓库下载的文件都会下载到这里

           3)Protobuf 源码下载

下载地址: https://github.com/protocolbuffers/protobuf/releases

选择 protobuf-java-3.7.1.zip  和 protoc-3.7.1-win64.zip

  解压 protobuf-java-3.7.zip 到本地某个目录下

     我下载到了F:\Project\protobuf\protobuf-3.7.1

    添加系统环境变量path  F:\Project\protobuf\protobuf-3.7.1\src 

将解压的protoc-3.7.1-win64.zip 里面的 bin/protoc.exe copy到 F:\Project\protobuf\protobuf-3.7.1\src

可以cmd输入命令 protoc –v 查看是否配置成功

4)编译Protobuf源码 获取 jar 包

打开CMD 切换到F:\Project\protobuf\protobuf-3.7.1\java目录下

运行 mvn install

开始编译

******************************************************************************************

这里遇到了一个搞了半天才搞定编译error

【No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?】

网上大都是Eclipse内编译出现的问题,所以都是在eclipse里设置里修改(但是我这里并没有用到eclipse)

其实本质问题是 maven的jdk和本地装的jdk版本不一致发生的这个问题,修改如下:

F:\Project\protobuf\protobuf-3.7.1\java\pom.xml

修改上面的文件如下:

<artifactId>maven-compiler-plugin</artifactId>

    <configuration>

        <fork>true</fork>

        <executable>C:\Program Files\Java\jdk1.8.0_131\bin\javac.exe</executable>

        <source>1.8</source>

        <target>1.8</target>

 </configuration>

 

编译完成后可以在F:\Project\protobuf\protobuf-3.7.1\java\core\target目录中找到protobuf-3.7.1.jar文件. 

到这里 这是我们的第一个产物,万里长征走了大半~~

二)protobuf根据我们结构化的数据生成的java文件

AS里建项目之前我们先添加protobuf组件到AS

File->settings->plugins->Browse repositories 搜索Protobuf Support

点击安装很快完成,这个是检验protobuf 语法的

AS里新建一个空的project

1)首先,我们需要在全局的buid.gradle文件中添加上protobuf工具插件:

classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6'

2)然后,要app/buid.gradle文件中:

    ①添加上此插件

        apply plugin: 'com.google.protobuf'

    ②添加依赖

         implementation 'com.google.protobuf:protobuf-java:3.7.1'

     ③添加protobuf 配置

protobuf {
    //配置protoc编译器
    protoc {
        artifact = 'com.google.protobuf:protoc:3.7.1'
    }
    //这里配置生成目录,编译后会在build的目录下生成对应的java文件
   generateProtoTasks {
        all().each { task ->
           task.builtins {
                remove java
           }
           task.builtins {
                java {}
           }
        }
    }
}

 ④    在Android添加 protobuf文件的目录

sourceSets {
      main {
          proto {
              srcDir 'src/main/java/com/gwrein/protobuftest'
          }
      }
}

3)在src/main/java/com/gwrein/protobuftest目录下添加文件TouchActionProto.proto,添加如下代码

syntax = "proto3";
message TouchActionProto{
    int32 action = 1;
    int32 x = 2;
    int32 y = 3;
}

Protobuf3 相较于以前版本 语法格式有一定的变化 中文翻译文档参考

https://blog.csdn.net/u011518120/article/details/54604615

 

4) 在AS buid项目 会将.proto 文件生成java文件

可以在\app\build\generated\source\proto\debug\java\ 目录下找到

这些生成的java文件封装好了一些API序列化和反序列化 ,这些API 可以直接在项目中调用 

 

3 项目中使用Protobuf

之前有见到百度CarLife 车机端源码中有用到过Protobuf, 这里以百度carlife的源码 介绍一下怎么使用protobuf

百度 Carlife 车机端 源码地址 https://github.com/ApolloAuto/apollo-DuerOS

1)把我们的产物jar文件添加到libs 文件夹下

百度carlife用的是老版本,但是不影响对本文的理解。

但是需要注意车机端和手机端 引用的protobuf的版本需要保持一致

2)添加 lib目录到app 的build.gradle里

dependencies {
    compile fileTree(include: ['*.jar'], exclude: ['android-support-v4.jar'], dir: 'libs')
    compile 'com.android.support:support-v4:22.2.0'
}

3)将protobuf生成的java文件添加到项目中

     

这里有很多这种文件都放到了一起,注意这些文件都是自动生成的,不要手动修改,要修改的话去前面的项目里修改

4)Protobuf 的使用

以下是车机端代码,将touch数据序列化(toByteArray)成字节数组 发送出去

import com.baidu.carlife.protobuf.CarlifeTouchActionProto.CarlifeTouchAction;
 public void sendAction(float x, float y, int action) {
        try {
            String mInfo = null;

            int tx = (int) (x * mPhoneContainerWidth / mContainerWidth);
            int ty = (int) (y * mPhoneContainerHeight / mContainerHeight);

            mInfo = "x = " + tx + " | y = " + ty + " | action = " + action;
            LogUtil.i(TAG, "sendActionEvent: " + mInfo);

            CarlifeCmdMessage command = new CarlifeCmdMessage(true);
            command.setServiceType(CommonParams.MSG_TOUCH_ACTION);
            CarlifeTouchAction.Builder builder = CarlifeTouchAction.newBuilder();
            //将结构体里的成员赋值
            builder.setX(tx);
            builder.setY(ty);
            builder.setAction(action);
            CarlifeTouchAction actionInfo = builder.build();
            //将actionInfo 对象序列化 然后打包到command里 发送出去
            command.setData(actionInfo.toByteArray());
            command.setLength(actionInfo.getSerializedSize());

            ConnectManager.getInstance().writeCarlifeTouchMessage(command);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

由于没有百度carlife 手机端代码 我这里进行了简单的code 用于说明 如何将接收到数据反序列化(解析成对象)

case CommonParams.MSG_TOUCH_ACTION:
        carlifeMsg = (CarlifeCmdMessage) msg.obj;
        CarlifeTouchAction touchAction= null;
        try {
            // 将序列化后的数据(字节型数组)解析成对象
            touchAction = CarlifeTouchAction.parseFrom(carlifeMsg.getData());
        } catch (InvalidProtocolBufferException e) {
            Log.e(TAG, "Getr Touch Action Info Error");
            e.printStackTrace();
            break;
        }
        //获取解析后结构数据
        int action = touchAction.getAction();
        int x = touchAction.getX();
        int y = touchAction.getY();

        MotionEvent event = null;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downTime = SystemClock.uptimeMillis();
                break;
        }
        // 根据获取额数据 生成motionEvent
        event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),action, x, y, 0);
        //将motionEvent 注入(这个事件只会分发到此应用中)
        mInstrumentation.sendPointerSync(event);
        break;

protobuf的使用 先总结这么多,也许有理解或总结不到位的地方,欢迎各路大神指出

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值