Proto DataStore에 대한 친절한 정보가 많이 없어서
제가 열심히 삽질해가며 작성한 글입니다... 😭
참고한 소스코드 : NowInAndroid
[versions]
# datastore
androidxDataStore = "1.1.1"
protobufPlugin = "0.9.4"
protobuf = "4.26.1"
junitJunit = "4.12"
[libraries]
# AndroidX
androidx-dataStore = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDataStore" }
androidx-dataStore-core = { group = "androidx.datastore", name = "datastore-core", version.ref = "androidxDataStore" }
androidx-dataStore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidxDataStore" }
# google protobuf
protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" }
protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" }
junit-junit = { group = "junit", name = "junit", version.ref = "junitJunit" }
[plugins]
# google protobuf
protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }
기능 세팅 전, libs.versions.toml 사전에 추가할 내용들.
미리 추가해두면 gradle에 implementation이 훨씬 수월해진다.
DataStore Module
1. Gradle 설정
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.hilt)
}
android {
namespace = "{packagename}.core.datastore"
}
dependencies {
api(libs.androidx.dataStore)
api(libs.androidx.dataStore.core)
api(libs.androidx.dataStore.preferences)
implementation(project(":core:common"))
implementation(project(":core:datastore-proto"))
}
2. DI DataStoreModule 객체 생성
/**
* < Proto DataStore >
* UserPreferences는 core:datastore-proto 모듈 안, user_preferences.proto 파일에 위치 (message)
*/
@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
@Provides
@Singleton
internal fun providesUserPreferencesDataStore(
@ApplicationContext context: Context,
@Dispatcher(IO) ioDispatcher: CoroutineDispatcher,
@ApplicationScope scope: CoroutineScope,
userPreferencesSerializer: UserPreferencesSerializer,
): DataStore<UserPreferences> =
DataStoreFactory.create(
serializer = userPreferencesSerializer,
scope = CoroutineScope(scope.coroutineContext + ioDispatcher),
) {
context.dataStoreFile("user_preferences.pb")
}
}
의존성 주입을 위해 모듈 객체를 생성해야 한다.
위치는 모듈 내 di 패키지를 만들어 클래스 파일 생성할 것을 권장한다.
이 소스에서 UserPreferences는 다음에 만들 datastore-proto 모듈 내에 생성될 예정이다.
3. 데이터 직렬화 - 역직렬화 담당 클래스를 생성한다.
class UserPreferencesSerializer @Inject constructor() : Serializer<UserPreferences> {
override val defaultValue: UserPreferences = UserPreferences.getDefaultInstance()
override suspend fun readFrom(input: InputStream): UserPreferences =
try {
UserPreferences.parseFrom(input)
} catch (exception: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", exception)
}
override suspend fun writeTo(t: UserPreferences, output: OutputStream) {
t.writeTo(output)
}
}
readFrom
- DataStore에서 데이터를 읽어오는 메서드
- Protobuf 파일을 사용할 경우, UserPreferences와 같은 데이터 구조를 InputStream에서 읽어서 프로토콜 버퍼 메시지로 변환하는 역할
writeTo
- DataStore에 데이터를 저장하는 메서드
- 주로 Protocol Buffers 형식으로 데이터를 저장
- 데이터를 OutputStream에 작성하는 작업을 수행하며, DataStore의 백그라운드 스레드에서 비동기적으로 호출되어야 한다
DataStore-Proto 모듈
1. datastore-proto gradle 세팅
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.protobuf)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "{packagename}.core.datastore.proto"
}
protobuf {
protoc {
artifact = libs.protobuf.protoc.get().toString()
}
generateProtoTasks {
all().forEach { task ->
task.builtins {
register("java") {
option("lite")
}
register("kotlin") {
option("lite")
}
}
}
}
}
// Android 프로젝트에서 프로토콜 버퍼(protobuf)로 생성된 소스 파일을 빌드 경로에 추가
// DataStore를 Proto 형식으로 사용할 때 프로토콜 버퍼로 생성된 코드를 소스 세트에 포함하기 위해 필요
androidComponents {
beforeVariants {
android.sourceSets.getByName(it.name) {
val buildDir = layout.buildDirectory.get().asFile
java.srcDir(buildDir.resolve("generated/source/proto/${it.name}/java"))
kotlin.srcDir(buildDir.resolve("generated/source/proto/${it.name}/kotlin"))
}
}
}
dependencies {
api(libs.protobuf.kotlin.lite)
}
gradle 작성 중 protobuf를 인식하지 못한다면 plugins 내에 alias(libs.plugins.protobuf) 를 선언해주고 sync를 한 번 해주면 import가 정상적으로 된다.
androidComponents 는 Android 프로젝트에서 프로토콜 버퍼(protobuf)로 생성된 소스 파일을 빌드 경로에 추가하기 위한 코드이다.
이 전 문서 참고.
2. user_preference.proto 파일 생성
syntax = "proto3";
option java_package = "{pakcagename}.core.datastore.proto";
option java_multiple_files = true;
message UserPreferences {
string user_key = 1;
string user_name = 2;
bool is_logged_in = 3;
}
파일 위치 : 모듈 패키지 > src > main > proto
절대 java 파일 내에 위치하면 안된다.
나는 처음 위치 생성을 잘못해서 파일을 인식하지 못해 하루동안 삽질했다 ㅠㅠ
3. Clean Project → Rebuild Project
이렇게까지 작성해도 DataStore 모듈 내에서는 UserPreferences 파일을 인식하지 못한다.
Rebuild를 한 번 해주면 build 폴더 내에 UserPreferencesKt.kt 파일이 생성되어 정상적으로 읽힌다.
나 같은 경우는 junit이 제대로 추가되지 않아 rebuild 시 오류가 발생하는데, 그래도 proto 파일을 읽는 데에는 문제가 없었다.
정상적으로 build가 성공된 소스코드
이걸 생성하기까지 얼마가 고되고 힘들었는가... 😭😭😭
너무 감격에 겨워 적는 글 💛
'Android > Jetpack' 카테고리의 다른 글
Preference DataStore와 Proto DataStore의 차이 (0) | 2024.11.05 |
---|---|
[Android/Jetpack]ViewModel + Databinding + LiveData (0) | 2023.02.24 |
[Android/Jetpack]LiveData (0) | 2023.02.24 |
[Android/Jetpack]Databinding 사용하기 (0) | 2023.02.24 |