数据格式篇(一):ProtoBuffer
阅读原文时间:2021年04月25日阅读:1

前言

自从年后回来,有一段时间没写博客了,首先是因为工作比较忙,其次是懒,没想到前几天竟然收到了第一笔打赏,在自己还没有完全变成咸鱼之前,赶紧翻个身。

前几天更新了Android Studio 3.1.0,出现了一些问题,还没有升级的朋友,如果不想浪费时间在调整项目上可以先等一等再更新。

一直没有找到特别好的话题,因为换了电脑,所以一些之前的一些练习用的项目都找不到了,之前断掉的系列得抓紧补上。今天聊一聊Protobuffer,这里肯定不会讲的特别详细,因为官方的教程已经非常棒了,学习链接:

官方网站:点击打开链接(需要翻墙)

阅读英文比较困难的朋友,建议安装个翻译插件,不得不说有些中文翻译的教程实在很尴尬。

正文

问:你都了解哪些数据格式?

答:Json,XML。

问:还有其他的吗?

答:……

为了避免上面尴尬的情况,我们应当了解更多的数据格式,随着产品的需求不断的变化,服务端和客户端的交互的数据也会变化,所以交互数据的体积,扩展,维护都面临着挑战,例如Json,随着版本的迭代,无法避免冗余的数据,有些已经不再使用的字段也不敢轻易删除,体积越来越大,维护也越来越麻烦。

我现在的项目使用的是FaceBook开源的Apollo-Graphql,再某些方面的确非常的方便,容错率很高,有兴趣的可以去github上看看,他最大的特点是可以将多个网络请求拼合成一个网络请求,降低每一次请求的网络开销。

我们今天的重点是ProtoBuffer,今天仅仅是一个了解和入门级的Demo,给大家展示一下基本的用法。

首先我们要在Android Studio中配置Protobuf:

1、下载插件

2、在Project中的build.gradle引入Protobuf的gradle插件,并设置相关配置。

dependencies {
        classpath 'com.android.tools.build:gradle:3.1.0'
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

3、在Module中使用protobuf插件。

apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'

android {
    ...
    protobuf {

        protoc {
            artifact = 'com.google.protobuf:protoc:3.0.0'
        }

        plugins {
            javalite {
                // The codegen for lite comes as a separate artifact
                artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
            }
        }

        generateProtoTasks {
            all().each { task ->
                task.builtins {
                    // In most cases you don't need the full Java output
                    // if you use the lite output.
                    remove java
                }
                task.plugins {
                    javalite {}
                }
            }
        }
    }

}

dependencies {
   ...
    // You need to depend on the lite runtime library, not protobuf-java
    compile 'com.google.protobuf:protobuf-lite:3.0.0'
}

具体的配置可以参考官方网站的教程,这里就不详细介绍了。

配置完成之后,我们编写第一个Protobuf文件。

在java文件夹同级下,创建proto文件夹,在proto文件夹中创建Book文件。

syntax = "proto3";
option java_package = "com.example.johnanna.protobuf.bean";
message Book {
    int32 id = 1;
    string name = 2;
    string desc = 3;
}

下面来介绍一下ProtoBuf的语法:

1、syntax 指定protobuf使用的语法版本,除了proto3还有proto2,proto3是高版本,推荐使用proto3,他可以和proto2互相兼容,所以不用担心。

2、生成文件的位置,我们编写的probuf文件会生成Java文件,我们可以随意设置生成文件的位置。

3、message标识的对象,可以说是消息体,使用protobuf的最终目标是和服务端通信,所以定义的都是交互数据中的内容,所以message这个单词非常的恰当。

4、定义变量的语法:类型 + 名称 = 唯一标识。这里要多说几句:int32和string是基本类型,紧接是变量名称,“=”后面的是唯一标识,记住是唯一标识!!不是赋值操作!!!标识是为了区分是否是同一个属性,保证属性不会匹配错乱,也许你有些懵逼,但是不要紧,之后我们再聊这个话题。

最后在MainActivity中使用这个Book:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        findViewById(R.id.button).setOnClickListener(this);
        writeBook();
    }

    private void writeBook() {
        new Thread(){
            @Override
            public void run() {
                BookOuterClass.Book book = BookOuterClass.Book.newBuilder()
                        .setId(1)
                        .setName("lzp")
                        .setDesc("good")
                        .build();

                File file = new File(getCacheDir().getAbsolutePath() + "/cache");
                if (file.exists()){
                    file.delete();
                }
                try {
                    book.writeTo(new FileOutputStream(file));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    @Override
    public void onClick(View v) {
        try {
            File file = new File(getCacheDir() + "/cache");
            BookOuterClass.Book book2 = BookOuterClass.Book.parseFrom(new FileInputStream(file));
            textView.setText(book2.toString());
        } catch (IOException e) {
            e.printStackTrace();
            textView.setText("error");
        }
    }
}

Book类存在于BookOuterClass中,创建使用Builder模式,我们在启动的时候,往File文件中写入了创建的Book对象,之后点击按钮读取这个对象,模仿和服务器通信的流程。

读取成功,我们的demo运行完美~

Protobuf的优点

看了一个略微low的demo,也没看出Protobuf有什么特别流弊的东西啊?如果你觉得太简单了,这只能说明Protobuf的设计者很流弊。Protobuf的最大的特点是流量小,而且非常小……

小到什么程度呢?官方的介绍:

如果属性的标识是1到15,会使用一字节的编码,如果是16到2047,则会使用两个字节编码。

在数据传输的时候,实际上传递的是一个个的数字编码,传输方负责把对象进行编码,接收方负责把对象进行解码,为了防止属性的编解码不一致,所以使用了唯一标识。

很遗憾,这里不能具体的感受到到底这个编解码的过程,大家可以到官网上查看编码的具体思想,你将会大吃一惊。

当然Protobuff还有很强的扩展性,其他的特性大家就自己去研究发现吧。

总结

今天我们了解了Protobuf,在数据格式方面又有了新的学习,Protobuf最大的特点就是数据体积小,如果是对流量要求非常高的话,一定要考虑一下。

ok,今天的内容就结束了,有什么问题,大家一起留言讨论,拜拜~

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章