前言
自从年后回来,有一段时间没写博客了,首先是因为工作比较忙,其次是懒,没想到前几天竟然收到了第一笔打赏,在自己还没有完全变成咸鱼之前,赶紧翻个身。
前几天更新了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'
}
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,今天的内容就结束了,有什么问题,大家一起留言讨论,拜拜~