Software Engineering/Android

[Android][Kotlin] SharedPreferences로 key-value pair 저장하기

iseop 2022. 1. 9. 00:00   인쇄용 버전

지난번 로또번호 가져오는 기능이 이어서, 입력한 로또 번호를 로컬 저장소에 저장할 수 있도록 기능을 추가해 보았습니다. DataStore라는 개선된 방식이 있다고 하는데, 저는 일단 간단하게 SharedPreference를 사용해 보았습니다.

메인 레이아웃 파일

 

ViewHolder 레이아웃 파일

 

패키지 구조

 

SharedPreferencesApplication.kt

이 Application을 추가로 등록함으로써 MainActivity뿐만 아니라 프로젝트 패키지 내 다른 곳에서도 사용할 수 있게 했습니다. 따라서 AndroidManifest.xml 내의 <Application> 태그 안쪽에 android:name="SharedPreferencesApplication" 속성을 추가해 주었습니다.

 

package org.iptime.iseop.lottochecker

import android.app.Application
import android.content.Context

class SharedPreferencesApplication : Application() {
    companion object {
        lateinit var SPM: PreferencesManager
    }

    override fun onCreate() {
        SPM = PreferencesManager(applicationContext)
        super.onCreate()
    }
}

class PreferencesManager(context: Context) {
    private val sharedPreferences = context.getSharedPreferences("file", Context.MODE_PRIVATE)

    fun getAll() : MutableMap<String, *> {
        return sharedPreferences.all
    }

    fun removeAll() {
        sharedPreferences.edit().clear().commit()
    }

    fun getString(key: String, defValue: String) : String {
        return sharedPreferences.getString(key, defValue).toString()
    }

    fun setString(key: String, value: String) {
        sharedPreferences.edit().putString(key, value).apply()
    }
}

 

AndroidManifest.xml

 

MainActivity.kt

이번에 코틀린에서 정규식을 처음 사용해 보았습니다. 저의 정규식과의 첫 만남은 옛날 Cisco ASA에서 MPF 설정(DPI 기능입니다.)을 할 때였는데, 오랜만입니다. "^[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+$"에서 ^는 시작, $는 끝을 의미하고, [0-9]+는 한자리 이상의 숫자를 의미합니다.

 

SharedPreferences에 값을 저장하고 RecyclerView를 갱신하는 부분은 

// Update listDataset for ItemAdapter and notify this update
listDataset = SP.SPM.getAll().keys.toList()
binding.list.adapter = ItemAdapter(this, listDataset)
binding.list.adapter?.notifyItemInserted(binding.list.adapter!!.itemCount)

이렇게 했습니다. 더 좋은 방법이 있을까요? 저는 이 단순한 앱이 복잡해지길 바라지 않습니다.

 

package org.iptime.iseop.lottochecker
...중략...
import org.iptime.iseop.lottochecker.SharedPreferencesApplication as SP

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Define "List" RecyclerView
        var listDataset = SP.SPM.getAll().keys.toList()
        binding.list.adapter = ItemAdapter(this, listDataset)

        // Show Welcome Dialog
        showWelcomeDialog()

        // "Add Button" OnClickListener
        binding.buttonAdd.setOnClickListener {
            val key = binding.editTextNumber.text.toString()
            val regex = Regex ("^[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+$")
            val validator = key.matches(regex)

            if (key == "") {
                Toast.makeText(applicationContext, "입력값 없음", Toast.LENGTH_SHORT).show()
            } else if (!validator) {
                Toast.makeText(applicationContext, "잘못된 번호", Toast.LENGTH_SHORT).show()
            } else {
                val confirm = SP.SPM.getString(key, NOT_AVAILABLE)
                
                // Check for duplications
                if (confirm == NOT_AVAILABLE) {
                	// Set item to SharedPreferences
                    SP.SPM.setString(key, key)
                    
                    // Update listDataset for ItemAdapter and notify this update
                    listDataset = SP.SPM.getAll().keys.toList()
                    binding.list.adapter = ItemAdapter(this, listDataset)
                    binding.list.adapter?.notifyItemInserted(binding.list.adapter!!.itemCount)
                    
                    Toast.makeText(applicationContext, "등록됨", Toast.LENGTH_SHORT).show()
                } else {
                    Toast.makeText(applicationContext, "중복값", Toast.LENGTH_SHORT).show()
                }
            }
        }

        binding.buttonDel.setOnClickListener {
            SP.SPM.removeAll()
            
            // Update listDataset for ItemAdapter and notify this update
            listDataset = SP.SPM.getAll().keys.toList()
            binding.list.adapter = ItemAdapter(this, listDataset)
            binding.list.adapter?.notifyItemInserted(binding.list.adapter!!.itemCount)
        }

        ...후략...

 

다음번에는 WorkManager를 이용해서 매주 토요일에 로또번호 체크 결과를 notification으로 알려주는 기능을 만들 예정입니다.