환영 기본 설정 DataStore 🚀
우리는 Android 앱에 일부 데이터를 로컬로 저장하기 위해 오랫동안 공유 기본 설정에 대해 작업하고 있으며 공유 기본 설정이 사용 사례를 지원하는 데 매우 유용하다는 것을 알고 있습니다.
우리의 삶을 더 쉽게 만들기 위해 Android는 더 효율적인 방식으로 앱에서 공유 기본 설정을 구현하기 위해 DataStore를 도입했습니다.
DataStore는 두 가지 유형의 구현을 제공합니다. 기본 설정 DataStore 및 Proto DataStore. 오늘 우리는 Preferences DataStore를 보고 있습니다.
So, why should we use Preferences DataStore? 😕
- It is an Async API that can be used via Flow
- It is safe to call on UI thread since work is moved to Dispatchers.IO under the hood
- It can signal errors
- It is safe from runtime exceptions
- It has a transactional API with strong consistency
- It handles data migration from Shared Preferences
이 친구는 몇 가지 장점이 있습니다. 😃
이제 바로 코드로 들어가 봅시다 💻
For this example I have used Dagger-Hilt to provide dependency Injection.
다음과 같이 build.gradle 파일을 업데이트합시다.
...
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
android {
...
// Compile options
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
dependencies {
....
// Preferences DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha01"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
// Kotlin coroutines components
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
....
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.dagger:hilt-android-gradle-plugin:2.28-alpha"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
이제 다음과 같이 Application 클래스 DataStore를 생성합니다.
@HiltAndroidApp
class DataStore: Application() {
override fun onCreate() {
super.onCreate()
}
}
다음으로 모든 로직이 들어갈 DataManager 클래스를 생성할 것입니다. 이 예에서는 사용자 이름, GitHub 사용자 이름 및 즐겨찾기 번호를 저장했습니다.
class DataManager(context: Context) {
private val dataStore = context.createDataStore("data_prefs")
companion object{
val USER_NAME = preferencesKey<String>("USER_NAME")
val USER_GITHUB = preferencesKey<String>("USER_GITHUB")
val USER_NO = preferencesKey<Int>("USER_NO")
}
suspend fun storeData(name:String, github:String, no:Int){
dataStore.edit {
it[USER_NAME] = name
it[USER_GITHUB] = github
it[USER_NO] = no
}
}
val userNameFlow:Flow<String> = dataStore.data.map {
it[USER_NAME] ?: ""
}
val userGithubFlow:Flow<String> = dataStore.data.map {
it[USER_GITHUB] ?: ""
}
val userNo: Flow<Int> = dataStore.data.map {
it[USER_NO] ?: -1
}
}
여기서 storeData 함수는 비동기로 만들고 우리는 코루틴을 사랑하기 때문에 일시 중단됩니다💛
다음으로 이 DataManager를 제공할 AppModule을 생성합니다.
@Module
@InstallIn(ApplicationComponent::class)
object AppModule {
@Singleton
@Provides
fun provideDataManager(@ApplicationContext context: Context) = DataManager(context)
}
이것은 우리 애플리케이션에 DataManager의 싱글톤을 제공할 것입니다.
다음과 같이 주요 활동에 대한 레이아웃을 만들 차례입니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="#0E0E0E">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:fontFamily="@font/poppins_medium"
android:text="Data Store Example"
android:textColor="#fff"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/tvTitle"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
android:backgroundTint="@color/colorPrimary"
android:textColor="#fff"
android:hint="Enter name"
android:textColorHint="#8C8C8C"
android:fontFamily="@font/poppins_medium"
android:layout_marginTop="50dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:id="@+id/etName"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/etName"
android:backgroundTint="@color/colorPrimary"
android:textColor="#fff"
android:hint="Github username"
android:textColorHint="#8C8C8C"
android:fontFamily="@font/poppins_medium"
android:layout_marginTop="20dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:id="@+id/etgithub"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/etgithub"
android:backgroundTint="@color/colorPrimary"
android:textColor="#fff"
android:hint="Enter favourite Number"
android:textColorHint="#8C8C8C"
android:fontFamily="@font/poppins_medium"
android:layout_marginTop="20dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:id="@+id/etNumber"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/etNumber"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="20dp"
android:backgroundTint="@color/colorPrimary"
app:cornerRadius="25dp"
android:text="SAVE"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:textColor="#fff"
android:id="@+id/btnSave"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/btnSave"
app:layout_constraintStart_toStartOf="parent"
android:text="No data saved to display!"
android:textColor="#fff"
android:textSize="16sp"
android:inputType="number"
android:id="@+id/tvName"
android:visibility="gone"
android:fontFamily="@font/poppins_medium"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="30dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tvName"
app:layout_constraintStart_toStartOf="parent"
android:text="No data saved to display!"
android:textColor="#fff"
android:textSize="16sp"
android:visibility="gone"
android:id="@+id/tvGithub"
android:fontFamily="@font/poppins_medium"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tvGithub"
app:layout_constraintStart_toStartOf="parent"
android:text="No data saved to display!"
android:textColor="#fff"
android:textSize="16sp"
android:id="@+id/tvNo"
android:visibility="gone"
android:fontFamily="@font/poppins_medium"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
드디어 MainActivity가 옵니다 😌
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var dataManager: DataManager
private var name:String = ""
private var github:String = ""
private var no:Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
subscribeToObservers()
btnSave.setOnClickListener {
val name:String = etName.text.toString()
val github:String = etgithub.text.toString()
val no:Int = etNumber.text.toString().toInt()
if (name.isNotEmpty() && github.isNotEmpty() && no!=-1){
GlobalScope.launch {
dataManager.storeData(name,github,no)
}
}else{
Toast.makeText(this, "Enter details carefully!", Toast.LENGTH_SHORT).show()
}
}
}
private fun subscribeToObservers() {
dataManager.userNameFlow.asLiveData().observe(this) {
name = it
if (name.isNotEmpty()){
tvName.visibility = View.VISIBLE
tvName.text = "Name: $name"
}
}
dataManager.userGithubFlow.asLiveData().observe(this) {
github = it
if (github.isNotEmpty()){
tvGithub.visibility = View.VISIBLE
tvGithub.text = "Github: $github"
}
}
dataManager.userNo.asLiveData().observe(this) {
no = it
if (no != -1){
tvNo.visibility = View.VISIBLE
tvNo.text = "Number: $no"
}
}
}
}
여기에서 기본 설정 키를 LiveData로 관찰하고 표시하도록 했습니다.
이 구현에서는 모든 것이 매우 매끄럽고 간단합니다. 😌
전체 코드 참조를 확인하려면 다음을 확인하십시오repository.
다음 이야기에서 만나요..
Reference
이 문제에 관하여(환영 기본 설정 DataStore 🚀), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/raystatic/welcome-preferences-datastore-88b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)