본문 바로가기
Mobile/Android

Android/Kotlin)Sharedpreferences 에서 Jetpack DataStore

by min_gui 2021. 10. 14.

구글 안드로이드 에서는 SharedPreferences 대신 DataStore 를 쓰도록 권장하고 있습니다.

 

Sharedpreferences

 

key-value 형식으로 데이터를 저장할수 있는 api 입니다. 주로 간단한 데이터나 로그인 데이터를 보관 했습니다.

저장 파일 은 .xml 입니다.

 

DataStore

Jetpack Datastore 는 프로토콜 버퍼를 사용해 key-value 또는 유형이 지정된 객체를 저장할수 있는 데이터 저장소 솔루션.

비동기적이고 일관된 트랜잭션 방식으로 데이터 저장합니다.

 

DataStore는 Preferences DataStore와 Proto DataStore라는 두 가지 구현을 제공합니다.

  • Preferences DataStore : 키를 사용하여 데이터를 저장하고 데이터에 액세스합니다. 이 구현은 유형 안전성을 제공하지 않으며 사전 정의된 스키마가 필요하지 않습니다.
  • Proto Datastore : 맞춤 데이터 유형의 인스턴스로 데이터를 저장합니다. 이 구현은 유형 안전성을 제공하며 프로토콜 버퍼를 사용하여 스키마를 정의해야 합니다.

※프로토콜 버퍼 

구글의 오픈소스 언어 이며, 구조화된 데이터를 직력화 하는 방식입니다. protobuf 또는 pb 로 부릅니다.

참고:  https://developers.google.com/protocol-buffers

 

preferences datastore 구현

 


1. build.gradle 에서 dependencies 추가. ( 1.0.0 현재 안정화 버전 )

dependencies {
    // Preferences DataStore
    implementation "androidx.datastore:datastore-preferences:1.0.0"

}

※버전 : https://developer.android.com/jetpack/androidx/releases/datastore

 

 

 

2. UserRepository.kt 생성.

//top level
private val Context.dataStroe : DataStore<Preferences> by preferencesDataStore(
    name = "settings"
)

class UserRepository(context: Context) {

	
    //내부에 context 를 받아 사용하는 Datastore 인스턴스를 만듭니다.
    private val mDataStore : DataStore<Preferences> = context.dataStroe
    
    //키값의 데이터타입 및 이름정의.
    private object PreferencesKeys {
        val KEY_NAME = stringPreferencesKey("name")
        val KEY_NUM = intPreferencesKey("num")
    }
    
   
    //데이터 읽기
    suspend fun readNum() : Int? {
        val preferences = mDataStore.data.first()
        return preferences[PreferencesKeys.KEY_NUM] ?: 0
    }

    suspend fun readName() :String? {
        val preferences = mDataStore.data.first()
        return preferences[PreferencesKeys.KEY_NAME] ?: "null"
    }
    
    
    
    //데이터 생성.
    suspend fun createStoreData() {
        mDataStore.edit { preferences ->
            preferences[PreferencesKeys.KEY_NUM] = 1111
            preferences[PreferencesKeys.KEY_NAME] = "James"
        }
    }
    
    
}

 

3. MainActivity.kt 생성

class MainActivity : AppCompatActivity() {

    lateinit var userRepository : UserRepository
    lateinit var dataName : String
    var dataNum : Int = 0
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        userRepository = UserRepository(applicationContext)
        
     	val tv_result = findViewById<TextView>(R.id.tv_result)
        val btn_read = findViewById<Button>(R.id.btn_read)
        
        //읽기 버튼 클릭
        btn_read.setOnClickListener {
            GlobalScope.launch {
                dataName=userRepository.readName()
                dataNum=userRepository.readNum()
                Log.e("test", dataName + " " + dataNum.toString())
     	}
        
        
        val btn_create = findViewById<Button>(R.id.btn_create)
        
        //데이터 생성 버튼 클릭
        btn_create.setOnClickListener {
            GlobalScope.launch {

                userRepository.createStoreData()
            }
        }
    
 }

 

데이터 생성 버튼을 누른후 읽기 버튼을 눌르면, 아래와 같이 로그로 데이터 값이 잘나온다. 

하지만 ui 에 표출 해줄 경우, 쓰레드 계층이 맞지 않아 오류가 발생한다. 

 

 

4. livedata 라이브러리 추가.

dependencies {
    // Preferences DataStore
    implementation "androidx.datastore:datastore-preferences:1.0.0"
    
    //Lifecycle components
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'

}

 

5. UserRepository.kt 에 val flownum, flowName 추가

class UserRepository(context : Context) {

...
...

	var flowNum: Flow<Int> = mDataStore.data
        .map { preferences ->
            preferences[PreferencesKeys.KEY_NUM] ?: 0
        }
    
	var flowName: Flow<String> = mDataStore.data
        .map { preferences ->
            preferences[PreferencesKeys.KEY_NAME] ?: ""
        }

 

6.MainActivity.kt 에 코드 추가

class MainActivity : AppCompatActivity() {

   ...
    
    override fun onCreate(savedInstanceState: Bundle?) {
    
    ...
    
   	userRepository.flowNum.asLiveData().observe(this, Observer {
            dataNum = it
            tv_result.setText(dataNum.toString()+" "+dataName)
        })

        userRepository.flowName.asLiveData().observe(this, Observer {
            dataName = it
            tv_result.setText(dataNum.toString()+" "+dataName)
        })

 

7.결과

create 버튼을 눌러. datastroe 키 값이 변경되면 observe 가 인지하여 화면 값을 변경 해줍니다.

 

 

마무리

sharedpreferences 보다 사전 지식(코루틴, livedata) 이 있어야 사용 가능..ㅠㅠㅠ

다음엔 Proto Datastore 공부. 

 

 

※참고 및 출처

https://developer.android.com/topic/libraries/architecture/datastore

 

Datastore  |  Android 개발자  |  Android Developers

Datastore   Android Jetpack의 구성요소. Jetpack Datastore는 프로토콜 버퍼를 사용하여 키-값 쌍 또는 유형이 지정된 객체를 저장할 수 있는 데이터 저장소 솔루션입니다. Datastore는 Kotlin 코루틴 및 Flow를

developer.android.com

 

 

 

'Mobile > Android' 카테고리의 다른 글

Android/Kotlin ) SQLlite 사용법.  (0) 2021.07.11
MVC 패턴 리사이클러뷰(Android RecyclerView)  (0) 2021.05.29