https://github.com/swjsw/ProtoDatastoreExample
datastore-protobuf 모듈은 Android의 Jetpack DataStore 라이브러리의 하위 모듈 중 하나로, Protocol Buffers를 사용하여 데이터를 저장하고 관리하는 데 사용되는 기능을 제공합니다. datastore-protobuf 모듈은 데이터를 Protocol Buffers 형식으로 직렬화하고 저장하며, 데이터의 유지 관리와 효율적인 변경 추적을 위해 사용됩니다.
Protocol Buffers는 Google에서 개발한 직렬화 데이터 포맷으로, 데이터 크기가 작고 직렬화/역직렬화 속도가 빠르며, 가독성이 좋지 않은 JSON이나 XML과 달리 구조화된 이진 데이터 형식을 사용합니다.
datastore-protobuf 모듈을 사용하여 데이터를 저장하고 관리하는 방법은 다음과 같습니다:
1. Gradle에 DataStore 의존성 추가하기 먼저, app의 build.gradle 파일에 DataStore의 의존성과 Protocol Buffers의 의존성을 추가해야 합니다.
plugins {
...
id "com.google.protobuf" version "0.9.1"
}
dependencies {
implementation "androidx.datastore:datastore-core:1.0.0"
implementation "com.google.protobuf:protobuf-javalite:3.18.0"
...
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.19.4"
}
// Generates the java Protobuf-lite code for the Protobufs in this project. See
// <https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation>
// for more information.
generateProtoTasks {
all().forEach { task ->
task.builtins {
create("java") {
option("lite")
}
}
}
}
}
- Error 해결 방법
- protobuf 버전을 “0.8.17”을 사용하게 되면 아래의 에러가 발생합니다.
- A problem occurred configuring project ':app'.
Could not get unknown property 'source' for generate-proto-generateDebugProto of type org.gradle.api.internal.file.DefaultSourceDirectorySet. - e: /Users/juj/work/tistory/ProtoDatastoreExample/app/build.gradle.kts:54:5: Unresolved reference: protoc
- 해결 방법 : protobuf 버전을 “0.9.1”로 변경
- A problem occurred configuring project ':app'.
- gradle에 “protobuf { }” 를 추가하지 않으면 아래의 에러가 발생합니다.
- Cause: error=2, No such file or directory
- 해결 방법 : protobuf { } 를 추가해 줍니다.
- protobuf 버전을 “0.8.17”을 사용하게 되면 아래의 에러가 발생합니다.
2. Proto 파일 정의하기: 데이터의 구조를 Protocol Buffers로 정의하는 .proto 파일을 작성해야 합니다. 이 파일은 데이터 구조를 정의하고 직렬화/역직렬화할 수 있는 코드를 생성합니다.
syntax = "proto3";
option java_package = "com.swjsw.example.protodatastore.data.repository.user";
option java_multiple_files = true;
message UserPreferences {
// filter for showing / hiding completed tasks
string name = 1;
string email = 2;
}
.proto 파일은 프로젝트의 리소스 디렉토리에 저장됩니다. 보통 src/main/proto 디렉토리 아래에 위치시키는 것이 일반적입니다. 이 디렉토리는 Android Gradle 프로젝트의 소스 디렉토리 구조에 포함되는 곳으로, 프로토 파일을 포함한 리소스 파일들을 저장하는데 사용됩니다.
다음은 프로젝트 구조에서 .proto 파일을 저장하는 위치의 예시입니다:
파일명은 sample.proto 입니다.
app
├── src
│ ├── main
│ │ ├── proto
│ │ │ ├── sample.proto
│ │ ├── java
│ │ ├── res
│ │ ├── ...
위의 예시에서 sample.proto 파일은 src/main/proto 디렉토리에 위치합니다. 이렇게 하면 Gradle 빌드 과정에서 .proto 파일이 컴파일되어 Kotlin 코드로 생성됩니다. 생성된 Kotlin 코드를 사용하여 Protocol Buffers 데이터를 다룰 수 있게 됩니다.
3. Serializer 만들기 proto 파일에 정의한 데이터 유형을 읽고 쓰는 방법을 Datastore에 알리려면 serializer를 구현해야 합니다. 또한 serializer는 디스크에 데이터가 없는 경우 반환될 기본값을 정의합니다.
object UserPreferencesSerializer : Serializer<UserPreferences> {
override val defaultValue: UserPreferences = UserPreferences.getDefaultInstance()
override suspend fun readFrom(input: InputStream): UserPreferences {
try {
return UserPreferences.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", exception)
}
}
override suspend fun writeTo(t: UserPreferences, output: OutputStream) = t.writeTo(output)
}
4. Proto DataStore 모듈 만들기
@InstallIn(SingletonComponent::class)
@Module
object DataStoreModule {
@Singleton
@Provides
fun provideProtoDataStore(@ApplicationContext appContext: Context): DataStore<UserPreferences> {
return DataStoreFactory.create(
serializer = UserPreferencesSerializer,
produceFile = { appContext.dataStoreFile(DATA_STORE_FILE_NAME) },
corruptionHandler = null
)
}
}
5. Proto DataStore로 데이타 읽고 / 쓰기
override val userName: Flow<String> = userPreferencesStore.data
.catch { exception ->
// dataStore.data throws an IOException when an error is encountered when reading data
if (exception is IOException) {
emit(UserPreferences.getDefaultInstance())
} else {
throw exception
}
}
.map { preferences ->
Log.d("datastore", "flowtest UserRepositoryImpl : userName : ${preferences.name}")
if (preferences.name.isNullOrEmpty()) {
DEFAULT_USER_NAME
} else preferences.name
}
// .flowOn(Dispatchers.IO) // datastore 는 기보적으로 IO 스레드에서 실행되지만 여기서는 명시적으로 지정, 없어도 무방함
override suspend fun getUserName(): String {
return userName.first()
}
override suspend fun setUserName(name: String) {
userPreferencesStore.updateData { preferences ->
preferences.toBuilder().setName(name).build()
}
}
DataStore 모듈과 사용 방법에 대해 자세한 설명은 다음에 추가할 예정입니다.
DataStroe 를 사용하는 예제는 아래의 링크에 있습니다.
아래 예제는 Hilt, ViewBinding, DataBiding, AAC ViewModel을 사용했고, MVVM 패턴의 구조를 가지고 있습니다.
https://github.com/swjsw/ProtoDatastoreExample
'Android > simple data 저장하기' 카테고리의 다른 글
Datastore - 구글 설명 (0) | 2023.08.31 |
---|---|
datastore-preferences 사용하기 (0) | 2023.08.30 |
DataStore 란? (0) | 2023.08.30 |
SharedPreferences 사용하기 (0) | 2023.08.29 |
simple data 저장 방법 (0) | 2023.08.29 |