Protocol Buffer 사용 및 전달하기
읽기 전
- 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
- 개인적으로 사용해보면서 배운 점을 정리한 글입니다.
단순 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()); // 확인을 위해 에러로그 출력
}
}
Person 이라는 구조 안에 string, int 형을 자유롭게 넣어 관리할 수 있었다.
nest 구조 형태의 protobuf 사용하기
앞서 정의했듯이 Person 구조 안에 PhoneNumber란 구조가 정의되어 있고 해당 구조는 string의 번호 값과 enum 형태의 PhoneType을 담을 수 있다. 그리고 Person 구조는 PhoneNumber에 repeated 필드를 설정하여 여러 개 가질 수 있다. (사람이 갖는 폰 번호, 집 번호 등 연락처는 다양하므로...)
userinfo.proto 부분
proto 구조를 정의할 떄 연락처는 1개라고 지정했었는데 조금 수정해서 repeated 필드를 갖는다고 하자. 그럼 아래와 같이 proto 파일의 해당 부분을 수정한 뒤 빌드하여 갱신해야 한다.
message Person { // Person 구조 정의
required string name = 1; // proto2에서는 required, oprional로 필수 여부 체크
required int32 id = 2;
optional string email = 3;
repeated PhoneNumber phone = 4; // 하위 protobuf 구조를 자식으로 가질 수 있음
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME]; // 입력되지 않으면 HOME으로 지정
}
enum PhoneType { // PhoneType의 각 속성값을 상수화
MOBILE = 0;
HOME = 1;
WORK = 2;
}
}
적당히 집번호와 휴대전화 연락처를 담은 1명의 protobuf 개체를 만드려면 아래와 같이 입력할 수 있다.
public class MainActivity extends AppCompatActivity {
Person protoPerson;
Person.Builder protoPersonBuilder;
@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";
String[] mNumberList = {"010-1234-5678", "064-123-4567"}; // rick의 번호들
Person.PhoneType[] mTypeList = {Person.PhoneType.MOBILE, Person.PhoneType.HOME};
protoPersonBuilder = Person.newBuilder(); // Builder객체 선언 후 입력 오픈
protoPersonBuilder.setId(mId)
.setName(mUserName)
.setEmail(mAddress); // rick의 정보 입력
for (int i = 0; i < 2; i++) {
Person.PhoneNumber.Builder phoneNumberBuilder = Person.PhoneNumber.newBuilder(); // 임시로 사용할 PhonNumber Builder 객체 선언 후 오픈
phoneNumberBuilder.setNumber(mNumberList[i])
.setType(mTypeList[i])
.build(); // 저장하여 닫기
protoPersonBuilder.addPhone(phoneNumberBuilder); // repeated 필드는 add를 사용
}
protoPerson = protoPersonBuilder.build(); // Builder 객체 저장하며 Person 입력
Log.e("MainAct: get person builder", protoPersonBuilder.toString());
Log.e("MainAct: get person", protoPerson.toString());
}
}
그리고 입력된 결과를 로그로 출력하면 아래와 같이 출력된다.
각각에 대해 접근하기 위해 사전에 정의한 protobuf를 build하면서 안드로이드가 자체적으로 생성한 메소드를 사용한다. 입력한 Person 개체에 어떤 메소드가 있는지 살펴보면 get-속성값 형태로 접근할 수 있음을 확인할 수 있고 repeated 필드의 경우 idx 값을 넣어 조회할 수 있다.
사람 이름과 두 번째 연락처에 접근하여 로그를 찍으면
Log.e("proto person name: ", protoPerson.getName());
Log.e("second phoneNumber", protoPerson.getPhone(1).getNumber());
아래와 같이 출력된다.
다음 Activity로 protobuf 전달하기
값을 입력하고 다음 페이지에서 입력했던 값들을 로드해 사용해야 할 때가 있다. 그럴 땐 평소 다른 값들을 intent에 넣어 전달했듯이 똑같이 해주면 된다. 다만 protobuf 자료형이 없으므로 Base64 String으로 Encoding 후 ByteArray로 변환하여 전달한다. 수신하는 Activity에서도 ByteArray를 받은 후 Base64 decoding을 하면 정상적으로 불러왔음을 확인할 수 있다.
MainActivity 부분
Log.e("MainAct: get person builder", protoPersonBuilder.toString());
Log.e("MainAct: get person", protoPerson.toString());
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("person", Base64.encodeToString(protoPerson.toByteArray(), Base64.DEFAULT));
startActivity(intent);
finish();
SecondActivity 부분
public class SecondActivity extends AppCompatActivity {
UserInfo.Person mPerson;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
try {
mPerson = UserInfo.Person.parseFrom(Base64.decode(getIntent().getStringExtra("person") ,Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
Log.e("SecondAct: get Person", mPerson.toString());
}
}
로그를 통해 확인하면 아래와 같다.
전체 코드
MainActivity.class
package com.example.myprotobuf;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import com.example.myprotobuf.UserInfo.Person;
public class MainActivity extends AppCompatActivity {
Person protoPerson;
Person.Builder protoPersonBuilder;
@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";
String[] mNumberList = {"010-1234-5678", "064-123-4567"};
Person.PhoneType[] mTypeList = {Person.PhoneType.MOBILE, Person.PhoneType.HOME};
protoPersonBuilder = Person.newBuilder();
protoPersonBuilder.setId(mId)
.setName(mUserName)
.setEmail(mAddress);
for (int i = 0; i < 2; i++) {
Person.PhoneNumber.Builder phoneNumberBuilder = Person.PhoneNumber.newBuilder();
phoneNumberBuilder.setNumber(mNumberList[i])
.setType(mTypeList[i])
.build();
protoPersonBuilder.addPhone(phoneNumberBuilder);
}
protoPerson = protoPersonBuilder.build();
Log.e("MainAct: get person builder", protoPersonBuilder.toString());
Log.e("MainAct: get person", protoPerson.toString());
Log.e("proto person name: ", protoPerson.getName());
Log.e("second phoneNumber", protoPerson.getPhone(1).getNumber());
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("person", Base64.encodeToString(protoPerson.toByteArray(), Base64.DEFAULT));
startActivity(intent);
finish();
}
}
SecondActicity.class
package com.example.myprotobuf;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import com.example.myprotobuf.UserInfo.Person;
public class SecondActivity extends AppCompatActivity {
Person mPerson;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
try {
mPerson = Person.parseFrom(Base64.decode(getIntent().getStringExtra("person") ,Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
Log.e("SecondAct: get Person", mPerson.toString());
}
}
참고자료
'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 사용하기 #001 (0) | 2020.10.19 |
Android | Splash screen 구현 (0) | 2020.05.19 |