본문 바로가기

[Android/Kotlin] 안드로이드 SharedPreferences 사용하기

꿈꾸는블로그왕 2021. 1. 20.

이번 시간에는 SharedPreferences를 좀 더 효율적으로 사용하는 방법에 대해서 알아보겠습니다.

 

안드로이드 개발 시 SharedPrefereces를 활용하여 간단한 상태값을 저장하기도 합니다.

 

최초 로그인 여부, 현재 로그인 유저의 간단한 정보, 가장 최근에 선택했던 값 등 다양하게 활용할 수 있습니다.

 

아래예제는 회원정보를 저장하고 조회하는 모습입니다.

 

 

[build.gradle/app]

// Preference
implementation 'androidx.preference:preference-ktx:1.1.1'

 

[PreferenceHelper.kt]

object PreferenceHelper {

    fun defaultPrefs(context: Context): SharedPreferences =
        PreferenceManager.getDefaultSharedPreferences(context)

    private inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) {
        val editor = this.edit()
        operation(editor)
        editor.apply()
    }

    operator fun SharedPreferences.set(key: String, value: Any?) {
        when (value) {
            is String? -> edit { it.putString(key, value) }
            is Int -> edit { it.putInt(key, value) }
            is Boolean -> edit{ it.putBoolean(key, value) }
            is Float -> edit { it.putFloat(key, value) }
            is Long -> edit { it.putLong(key, value) }
            else -> throw UnsupportedOperationException("Error")
        }
    }

    @Suppress("UNCHECKED_CAST")
    operator fun <T> SharedPreferences.get(key: String, defaultValue: T? = null): T {
        return when (defaultValue) {
            is String, null -> getString(key, defaultValue as? String) as T
            is Int -> getInt(key, defaultValue as? Int ?: -1) as T
            is Boolean -> getBoolean(key, defaultValue as? Boolean ?: false) as T
            is Float -> getFloat(key, defaultValue as? Float ?: -1f) as T
            is Long -> getLong(key, defaultValue as? Long ?: -1) as T
            else -> throw UnsupportedOperationException("Error")
        }
    }

}

SharedPreferences를 관리하는 Helper클래스입니다.

코틀린에서는 배열이나 맵의 원소에 접근할 때 대괄호를 사용할 수 있습니다. 이를 인덱스 연산자라고 하며 이를 사용하기 위해서 operator set / operator get 을 만들어 주었습니다. 호출 시 타입에 따라서 저장하고 불러 올 수 있습니다.

확장함수 edit을 만들어 사용했습니다.

 

 

[SharedManager.kt]

class SharedManager(context: Context) {

    private val prefs: SharedPreferences = PreferenceHelper.defaultPrefs(context)

    fun saveCurrentUser(user: User) {
        prefs["name"] = user.name
        prefs["age"] = user.age
        prefs["email"] = user.email
        prefs["password"] = user.password
        prefs["isMarried"] = user.isMarried
    }

    fun getCurrentUser(): User {
        return User().apply {
            name = prefs["name", ""]
            age = prefs["age", 0]
            email = prefs["email", ""]
            password = prefs["password", ""]
            isMarried = prefs["isMarried", false]
        }
    }

}

 

set, get을 import하지 않으면 에러가 발생합니다.

import com.reachfree.enhancedsharedpreferences.PreferenceHelper.set
import com.reachfree.enhancedsharedpreferences.PreferenceHelper.get

 

[User.kt]

data class User(
    var name: String? = null,
    var age: Int? = 0,
    var email: String? = null,
    var password: String? = null,
    var isMarried: Boolean? = false
)

 

 

[MainActivity.kt]

class MainActivity : AppCompatActivity() {
    
    private var _binding: ActivityMainBinding? = null
    private val binding get() = _binding!!

    private val sharedManager: SharedManager by lazy { SharedManager(this) }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        _binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.btnSave.setOnClickListener {
            // validate 생략
            val currentUser = User().apply {
                name = binding.edtName.text.toString().trim()
                age = binding.edtAge.text.toString().toInt()
                email = binding.edtEmail.text.toString().trim()
                password = binding.edtPassword.text.toString().trim()
                isMarried = binding.switchIsMarried.isChecked
            }
            sharedManager.saveCurrentUser(currentUser)
        }

        binding.btnSearch.setOnClickListener {
            val currentUser = sharedManager.getCurrentUser()
            val result = "name: ${currentUser.name} \n" +
                    "age: ${currentUser.age} \n" +
                    "email: ${currentUser.email} \n" +
                    "password: ${currentUser.password} \n" +
                    "isMarried: ${currentUser.isMarried}"

            binding.txtResult.text = result
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

 

 

[activity_main.xml]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/edt_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Name"
        android:importantForAutofill="no"
        android:inputType="textCapSentences" />

    <EditText
        android:id="@+id/edt_age"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Age"
        android:importantForAutofill="no"
        android:inputType="number" />

    <EditText
        android:id="@+id/edt_email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Email"
        android:importantForAutofill="no"
        android:inputType="textEmailAddress" />

    <EditText
        android:id="@+id/edt_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="password"
        android:importantForAutofill="no"
        android:inputType="textPassword" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:text="Are you Married?"
            android:layout_weight="1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Switch
            android:id="@+id/switch_is_married"
            android:gravity="end"
            android:layout_weight="1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </LinearLayout>

    <Button
        android:id="@+id/btn_save"
        android:text="저장하기"
        android:layout_marginTop="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_search"
        android:text="조회하기"
        android:layout_marginTop="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:text="현재 유저"
        android:layout_marginTop="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/txt_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

 

 

 

 

 

 

 

 

 

 

 

댓글