protobuf在java, Android下的使用总结

简介: protobuf在java, Android下的使用总结

protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库(类似Json),但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。后面将会有简单的demo对于这两种格式的数据转化效率的对比。但这个库目前使用还不是太流行,据说谷歌内部很多产品都有使用。


Protobuf的优点


1,性能好,效率高


2,代码生成机制,数据解析类自动生成


3,支持向后兼容和向前兼容


4,支持多种编程语言(java,c++,python)


可用来做什么?


       Protobuf可替代Json,支持Java、C++、Python等语言,简单好用还节省内存流量,可利用Protobuf进行改造,替换原有的Json或者XML存储方式进一步提升性能。还可用在RPC远程过程调用,及客户端、服务器端通信和数据交换。


       Xml、Json是目前常用的数据交换格式,它们直接使用字段名称维护序列化后类实例中字段与数据之间的映射关系,一般用字符串的形式保存在序列化后的字节流中。消息和消息的定义相对独立,可读性较好。但序列化后的数据字节很大,序列化和反序列化的时间较长,数据传输效率不高。


       Protobuf和Xml、Json序列化的方式不同,采用了二进制字节的序列化方式,用字段索引和字段类型通过算法计算得到字段之前的关系映射,从而达到更高的时间效率和空间效率,特别适合对数据大小和传输速率比较敏感的场合使用。


protobuf转换过的二进制文件具有:


空间效率


Json:107个字节


Protobuf:32个字节


时间效率


Json序列化: 1ms ,  反序列化:0ms


Protobuf 序列化: 0ms 反序列化:0ms


将public List<Phone> list和repeated PhoneInfo phoneInfoList =3;都赋值为1000个PhoneInfo


空间效率


Json:4206个字节


Protobuf:1332个字节


时间效率


Json序列化: 4ms ,  反序列化:1ms


Protobuf 序列化: 1ms 反序列化:0ms


优点:通过以上的时间效率和空间效率,可以看出protobuf的空间效率是JSON的2-5倍,时间效率要高,对于数据大小敏感,传输效率高的模块可以采用protobuf库。


缺点:消息结构可读性不高,序列化后的字节序列为二进制序列不能简单的分析有效性;目前使用不广泛,只支持java,C++和Python;


使用:


1.首先要在adroid stdio工程根路径下,就是和settings.gradle在同一级目录的build.gradle文件中添加protobuf插件classpath配置。


dependencies {
    classpath 'com.android.tools.build:gradle:3.0.1'
    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.2'


2.在app中的build.gradle添加两个protobuf依赖库:protobuf-java和protoc(如图:app模块中添加protobuf依赖库.png)。protobuf-java是用来处理java代码的,protoc是处理C或者C++代码的。



apply plugin: 'com.google.protobuf'


implementation 'com.google.protobuf:protobuf-java:3.1.0'
implementation 'com.google.protobuf:protoc:3.1.0'


3.接着还需要在build.gradle的“android { }”中进行配置自动生成代码的sourceSets目录路径。


sourceSets {
    main {
        java {
            srcDir 'src/main/java'
        }
        proto {
            srcDir 'src/main/proto'
            include '**/*.proto'
        }
    }
}


3-1.自动生成的java资源路径:srcDir 'src/main/java'


3-2. 自动生成的proto资源路径:srcDir 'src/main/proto' 和包括后缀为.proto的文件。


//构建task
protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.1.0'
    }
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}
                // Add cpp output without any option.
                // DO NOT omit the braces if you want this builtin to be added.
                cpp {}
            }
        }
    }
    //生成目录
    generatedFilesBaseDir = "$projectDir/src/generated"
}


4.接下来,在配置的指定位置,即“src/main/”的路径下创建名字为“proto”的文件夹。在“proto”路径下创建.proto为后缀的文件再写上proto格式的代码。


点击“Sync”同步按钮,同步整个工程,protobuf的java代码就会自动生成了,不过生成的是在app/src/genarated文件夹下。使用时


直接import引用过来即可。


举例,一个测试的小demo:


*.proto文件如下:



读写测试demo:


package com.example.yang.myapplication.protobuf;
import  com.yangyongzhen.bean.Testpro;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Testprotobuf {
    public static final String FILE_NAME_READ="testpro.txt";
    public static final String FILE_NAME_WRITE="testpro1.txt";
    public static void main(String[] args) throws IOException {
        System.out.println("protobuf test:");
       //写测试
        Testpro.response.Builder respb = Testpro.response.newBuilder();
        respb.setLedOn(10);
        respb.setNodeId("12345");
        respb.setParentId("67890");
        respb.setUuid("987654321");
        Testpro.response resp = respb.build();
        File file=new File(FILE_NAME_WRITE);
        FileOutputStream outputStream = new FileOutputStream(file);
        resp.writeTo(outputStream);
        //读测试
        File file1=new File(FILE_NAME_READ);
        FileInputStream inputStream = new FileInputStream(file1);
        Testpro.response resp1 = Testpro.response.parseFrom(inputStream);
        int t = resp1.getLedOn();
        System.out.println(t);
        String str = resp1.getNodeId();
        System.out.println(str);
        str = resp1.getParentId();
        System.out.println(str);
        str = resp1.getUuid();
        System.out.println(str);
    }
}


输出结果:


protobuf test:


1


5149013220584027


5149013108519750


121212121


相关文章
|
2月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
129 1
|
3月前
|
存储 搜索推荐 Java
探索安卓开发中的自定义视图:打造个性化UI组件Java中的异常处理:从基础到高级
【8月更文挑战第29天】在安卓应用的海洋中,一个独特的用户界面(UI)能让应用脱颖而出。自定义视图是实现这一目标的强大工具。本文将通过一个简单的自定义计数器视图示例,展示如何从零开始创建一个具有独特风格和功能的安卓UI组件,并讨论在此过程中涉及的设计原则、性能优化和兼容性问题。准备好让你的应用与众不同了吗?让我们开始吧!
|
3月前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
74 1
|
3月前
|
Java Android开发
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
473 1
|
3月前
|
Android开发
Cannot create android app from an archive...containing both DEX and Java-bytecode content
Cannot create android app from an archive...containing both DEX and Java-bytecode content
35 2
|
3月前
|
IDE Java Linux
探索安卓开发:从基础到进阶的旅程Java中的异常处理:从基础到高级
【8月更文挑战第30天】在这个数字时代,移动应用已经成为我们日常生活中不可或缺的一部分。安卓系统由于其开放性和灵活性,成为了开发者的首选平台之一。本文将带领读者踏上一段从零开始的安卓开发之旅,通过深入浅出的方式介绍安卓开发的基础知识、核心概念以及进阶技巧。我们将一起构建一个简单的安卓应用,并探讨如何优化代码以提高性能和应用的用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和启发。
|
4月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
【7月更文挑战第28天】在 Android 开发中, NDK 让 Java 与 C++ 混合编程成为可能, 从而提升应用性能。**为何选 NDK?** C++ 在执行效率与内存管理上优于 Java, 特别适合高性能需求场景。**环境搭建** 需 Android Studio 和 NDK, 工具如 CMake。**JNI** 构建 Java-C++ 交互, 通过声明 `native` 方法并在 C++ 中实现。**实战** 示例: 使用 C++ 计算斐波那契数列以提高效率。**总结** 混合编程增强性能, 但增加复杂性, 使用前需谨慎评估。
140 4
|
4月前
|
SQL Java Unix
Android经典面试题之Java中获取时间戳的方式有哪些?有什么区别?
在Java中获取时间戳有多种方式,包括`System.currentTimeMillis()`(毫秒级,适用于日志和计时)、`System.nanoTime()`(纳秒级,高精度计时)、`Instant.now().toEpochMilli()`(毫秒级,ISO-8601标准)和`Instant.now().getEpochSecond()`(秒级)。`Timestamp.valueOf(LocalDateTime.now()).getTime()`适用于数据库操作。选择方法取决于精度、用途和时间起点的需求。
65 3
|
5月前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
39 3
Android面试题之Java 泛型和Kotlin泛型
|
5月前
|
存储 Java 数据库连接
Android Java开发异步
【6月更文挑战第15天】