Protocol Buffer 소개 및 import 하기
읽기 전
- 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
- 개인적으로 사용해보면서 배운 점을 정리한 글입니다.
Protocol Buffer란
Google에서 개발한 오픈소스 직렬화 데이터 구조이다. 프로젝트 중 PM을 담당하신 선배가 적극 추천해주셔서 사용해본 결과 JSON과 유사한 느낌을 받았다. C++, C#, Python, Java 등 다양한 언어를 지원하고 있다. 이번 포스팅에서는 사이드 프로젝트로 참가하고 있는 안드로이드 어플리케이션 개발 환경에서의 사용에 대해 다뤄보고자 한다.
Protocol Buffer의 장점
통상적으로 개발자들이 말하는 장점은 두 가지가 있다. 같은 데이터라도 속성을 상수화하여 크기를 줄이기에 JSON 등을 다룰 때보다 데이터의 크기가 덜하고 이 점으로 인해 속도 개선 효과를 거둘 수 있다는 점과 Protocol Buffer에서 다시 JSON 등으로 converting하기 용이하다는 점이다.
개인적으로 가장 와닿은 장점으로는 하나의 class처럼 여러가지 자료형 뿐만 아니라 상위 protobuf 구조 안에 또 다른 protobuf 구조를 넣어 관리하기 매우 용이했다는 점과 String으로 변환 후 저장하고 다시 로드하여 protobuf로 바꿀 때에도 몇 가지가 유의하면 그대로 인식할 수 있어 꽤나 인상깊었다.
Android에서 Protocol Buffer 사용하기
build.gradle (project)
Android project의 build.gradle에 다음과 같이 dependency를 추가한다. 최신 버전은 0.8.13이나 프로젝트에서는 0.8.12가 쓰였기에 사용하고 있는 버전을 사용하였다.
buildscript {
dependencies {
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.12"
}
}
build.gradle(Module)
첫 번째로 가장 상단에 plugin 선언을 한다.
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf' // add protobuf plugin
기본적으로 작성되어 있는 dependencies 아래에 공식 깃헙 레퍼런스를 참고하여 아래와 같이 추가한다.
dependencies {
// You need to depend on the lite runtime library, not protobuf-java
implementation 'com.google.protobuf:protobuf-javalite:3.8.0'
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.8.0'
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
}
}
}
}
.proto파일 정의하기
빌드하기 전 기본적인 protobuf 구조를 정의한다. 우선 공식가이드의 예시 구조를 차용하기로 한다. 프로젝트 구조 트리를 보면 main 폴더 하단에 java, res 폴더가 있음을 확인할 수 있다. 마찬가지로 main 폴더 하단에 proto 폴더를 생성한 뒤, proto 폴더 안에 적당히 userinfo.proto 텍스트 파일을 생성한다.
syntax = "proto2";
package com.example.myprotobuf;
option java_package = "com.example.myprotobuf";
option java_outer_classname = "UserInfo"; // 다른 액티비티에서 불러올 때 사용할 이름
message Person { // Person 구조 정의
required string name = 1; // proto2에서는 required, oprional로 필수 여부 체크
required int32 id = 2;
optional string email = 3;
optional PhoneNumber phones = 4; // 하위 protobuf 구조를 자식으로 가질 수 있음
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME]; // 입력되지 않으면 HOME으로 지정
}
enum PhoneType { // PhoneType의 각 속성값을 상수화
MOBILE = 0;
HOME = 1;
WORK = 2;
}
}
message AddressBook {
repeated Person people = 1;
}
required는 입력되지 않으면 안되는 필수 값들을 의미하며 optional은 있어도, 없어도 상관없는 값들을 의미한다. proto3에서는 required, optional 모두 삭제되어 기본형이 optional로 통일되는데 그 이유를 찾아보았다.
required로 사전에 고정해버리면 구버전의 application들은 새로은 required 필드에 해당하는 값을 제공하지 않아 제대로 작동할 수 없다는 문제가 있으며 이미 정의한 required 필드를 후에 수정하려면 새로운 필드를 생성하고 이전에 만든 필드를 ignore해야 하기 때문이라고 설명한다. 그리고 시스템의 복잡성이 증가할 수록 여기저기서 참조함에 따라 .proto 구조의 사용범위가 넓어지는데 strict하게 정의된 required 필드는 빈번한 시스템 다운의 원인이 될 수 있다는 이유도 첨부하고 있다.
protobuf에 값 입력 후 로그로 찍어보기
package com.example.myprotobuf;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.example.myprotobuf.UserInfo.Person;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Integer mId = 1;
String mUserName = "rick";
String mAddress = "asdf1234@gmail.com";
Person protoPerson = Person.newBuilder() // 값을 입력할 경우 newBuilder로 열어야 함
.setId(mId)
.setName(mUserName)
.setEmail(mAddress) // 사전에 정의한 값들을 정의된 자료형에 맞게 입력
.build(); //입력을 끝내면 build로 저장한다.
Log.e("get protobuf", protoPerson.toString()); // 확인을 위해 에러로그 출력
}
}
E/get protobuf: # com.example.myprotobuf.UserInfo$Person@c93e7103
email: "asdf1234@gmail.com"
id: 1
name: "rick"
참고자료
'Android' 카테고리의 다른 글
Android | 다중 SNS 로그인 연동 #001 - KAKAO (4) | 2020.10.29 |
---|---|
Android | 해시 키 생성 및 릴리즈 용 키 생성 (0) | 2020.10.27 |
Android | Android에서 Protocol Buffer 사용하기 #003 (0) | 2020.10.26 |
Android | Android에서 Protocol Buffer 사용하기 #002 (0) | 2020.10.26 |
Android | Splash screen 구현 (0) | 2020.05.19 |