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 |