【Android】SharedPreferenceManagerをスマートに実装する【Kotlin】

こんにちは!

今回はSharedPreferenceManagerをスマートに実装したいと思います!

※スマートには個人差があります。

SharedPreferenceとは?

データをアプリキルされてもデバイス内に保持するための仕組み。Key-Value形式で保存する必要がある

内部ではどういう仕組みかというと

SharedPreferenceに保存されるとアプリ内に用意されるSharedPreference用のXMLファイルにデータが定義され、保存できると言う仕組みが行われています。

実装

まずはコードを記述します。後ほど説明します。

package com.example.androidstudy

import android.content.Context
import java.lang.IllegalArgumentException
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

@Suppress("UNCHECKED_CAST")
class SharedPreferenceManager private constructor(context: Context) {
    private val sharedPreferences = context.getSharedPreferences("app_preference", Context.MODE_PRIVATE)

    companion object {
        private lateinit var staticContext: Context
        private var instance: SharedPreferenceManager? = null

        fun getInstance() = instance ?: synchronized(this) {
            instance ?: SharedPreferenceManager(staticContext).also { instance = it }
        }

        fun initialize(context: Context) {
            instance = SharedPreferenceManager(context)
            staticContext = context
        }
    }

    // 登録したいデータを変数に定義していく
    var loginId: String? by preference()
    var isLogin: Boolean? by preference()
    var age: Int? by preference()

    // 変数がset/getを委譲する処理を記述
    private fun <T : Any?> preference() = object : ReadWriteProperty<SharedPreferenceManager, T?> {
        override fun setValue(thisRef: SharedPreferenceManager, property: KProperty<*>, value: T?) {
            putData(property.name, value)
        }

        override fun getValue(thisRef: SharedPreferenceManager, property: KProperty<*>): T? {
            return sharedPreferences.all[property.name] as? T?
        }
    }

    // データをキーに応じて保存
    private fun <T : Any?> putData(key: String, value: T?) {
        val editor = sharedPreferences.edit()
        when (value) {
            is String -> editor.putString(key, value)
            is Boolean -> editor.putBoolean(key, value)
            is Float -> editor.putFloat(key, value)
            is Int -> editor.putInt(key, value)
            is Long -> editor.putLong(key, value)
            null -> editor.remove(key)
            else -> throw IllegalArgumentException("type mismatch")
        }
        editor.apply()
    }
}

getInstance()の説明

SharedPreferenceManagerのインスタンスをシングルトンで取得するメソッド

シングルトン = デザインパターンの一つで、実行時にそのクラスのインスタンスが必ずひとつになるよう設計すること

データ保存、取得で毎度インスタンス生成する必要性がないのでシングルトンで実装しています。

initialize()の説明

SharedPreferenceManagerのインスタンス作成時に必ず呼び出さないといけないメソッド

SharedPreferenceManagerのインスタンス作成にContextが必要なのでgetInstanceの引数としてContextを用意しないといけないのでActivityやFragment以外のクラスから呼び出しづらくなります。

初回インスタンス作成時にinitialize()でContextを設定してgetInstanceの引数不要を実現しています。

preference()の説明

データ保存用変数のsetter/getterが委譲されるメソッド

setter/getterを共通化して他のデータ保存用変数に使用できるようにしています。

putData()の説明

SharedPreferenceにデータを保存するためのメソッド

SharedPreferenceには保存できるデータ型が複数あるのでジェネリクス型を使用してさまざまな型のデータを保存できるようにしています。

ジェネリクス型 = 任意の型が使用できるようになります。

身近で使用しているもので言うとArrayList<String>()等で使用していますね

使用例

前提準備

Applicationクラスに下記を記述する

override fun onCreate() {
    super.onCreate()
    // インスタンスを初期化
    SharedPreferenceManager.initialize(applicationContext)
}

データを保存する場合

// ログインIDを保存
SharedPreferenceManager.getInstance().loginId = "hoge"
// ログイン済みフラグを保存
SharedPreferenceManager.getInstance().isLogin = true
// 年齢を保存
SharedPreferenceManager.getInstance().age = 41

データを取得する場合

// ログインIDを取得
val loginId = SharedPreferenceManager.getInstance().loginId
// ログイン済みフラグを取得
val isLogin = SharedPreferenceManager.getInstance().isLogin
// 年齢を取得
val age = SharedPreferenceManager.getInstance().age

最後に

いかがでしたでしょうか

enumや型に応じたsetter/getterを使用していないので個人的にはスマートかなと思っています。

「もっとスマートに書けるぞ」等ありましたらコメントの程よろしくお願いします。

コメント

タイトルとURLをコピーしました