【Android/Kotlin】SharedPreferencesでデータを永続化する

## やりたいこと
ユーザーの入力(EditText)を永続化し、アプリ起動のたびに初期化されないようにしたい。
## 開発環境
* macOS 10.15.5
* Android Studio 4.0
* Kotlin 1.3.72

## SharedPreferencesとは？
SharedPreferences とは、boolean, float, int, long, string などのデータ型について、キーと値のペアを読み書きできるAPI。キーと値のペアは内部ストレージにxmlファイルとして保存される。初回アクセス以降はメモリ上に展開されたキャッシュからデータを取得するため、高速にアクセスできる。

API名「SharedPreferences」から誤解されることもあるが、厳密には「ユーザー設定」を保存するためのものではなく、ユーザーのハイスコアなどの単純なデータを保存する際に使われる。↓ デベロッパーガイドより
> 注: [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) API は Key-Value ペアの読み書き用であり、アプリ設定向けのユーザー インターフェースを作成するための [Preference](https://developer.android.com/reference/android/preference/Preference) API と混同しないように注意してください（ただし、後者もユーザー設定の保存には [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) を使用します）。[Preference](https://developer.android.com/reference/android/preference/Preference) API の詳細については、[設定デベロッパー ガイド](https://developer.android.com/guide/topics/ui/settings)をご覧ください。

## 使い方
#####まず、次のいずれかのメソッドを呼び出し、`SharedPreferences`オブジェクトを取得する。

* `getSharedPreferences()`
アプリの任意のContextから呼び出せる。

* `getPreferences()`
一つのActivityに対してプリファレンスファイルを一つだけ使用する必要がある場合に、Activityからこのメソッドを使用する。

```Kotlin
val sharedPref = getSharedPreferences("プリファレンスファイル名", Context.MODE_PRIVATE)
```
*第二引数はファイルの共有モードで`Context MODE＿PRIVATE`は他のアプリとデータを共有しない設定。↓他のモードについては非推奨になっているそうです。(デベロッパーガイドより)
> 注: MODE_WORLD_READABLE モードと MODE_WORLD_WRITEABLE モードは、API レベル 17 でサポートが終了しています。Android 7.0（API レベル 24）以降は、サポートが終了したモードを使用すると SecurityException がスローされます。アプリ専用のファイルを他のアプリと共有する必要がある場合は、FileProvider を使用して FLAG_GRANT_READ_URI_PERMISSION を指定してください。 詳細については、ファイルを共有するをご覧ください。

##### ファイルへの書き込み

* `SharedPreferences.edit()`メソッドでEditorを作成
* `putInt()`や`putString()`を呼び出し、Key-Valueを渡す
* `apply()`または`commit()`を呼び出して、変更内容を保存

```Kotlin
sharedPref.edit().putString("key名", inputText).apply()
```
*`apply()`は非同期、`commit()`は同期的にディスクに書き込む。

##### ファイルから読み取る
* `getInt()`や`getString()`を呼び出し、値に対応するキーを指定する
* 必要に応じて、キーが存在しない場合に返すデフォルト値を指定する

```Kotlin
val savedText = sharedPref.getString("key名", "デフォルト文字列")
```

## サンプルコード

レポジトリは[こちら](https://github.com/taowata/SharedPreferencesSample)。

```MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // getSharedPreferencesメソッドでSharedPreferencesオブジェクトを取得
        val sharedPref = getSharedPreferences("プリファレンスファイル名", Context.MODE_PRIVATE)

        // getString()を呼び出して保存されている文字列を読み込む
        // まだ保存されていない場合はデフォルトの文字列を返す
        val savedText = sharedPref.getString("key名", "デフォルト文字列")

        val editText = findViewById<EditText>(R.id.editText)
        editText.setText(savedText)

        val button = findViewById<Button>(R.id.saveButton)
        button.setOnClickListener {
            // テキストボックスに入力されている文字列を取得
            val inputText = editText.text.toString()
            // プリファレンスに書き込む
            sharedPref.edit().putString("key名", inputText).apply()
        }
    }
```
## xmlファイルが実際に保存されている場所の確認
AndroidStudio の Device File Explorerから確認できます。(詳しくは[こちら](https://minpro.net/sharedpreferences))

## 参考
* デベロッパーガイド
    * [データとファイルのストレージの概要](https://developer.android.com/guide/topics/data/data-storage#pref) 
    * [Key-Value データを保存する](https://developer.android.com/training/data-storage/shared-preferences)
* みんなのプログラミング 
    * [[Android]SharedPreferencesファイルの正体と保存場所](https://minpro.net/sharedpreferences)
* 書籍(Amazonのリンク)
    * [基本からしっかり身につくAndroidアプリ開発入門 Android](https://www.amazon.co.jp/%E5%9F%BA%E6%9C%AC%E3%81%8B%E3%82%89%E3%81%97%E3%81%A3%E3%81%8B%E3%82%8A%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%8FAndroid%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-Android-Studio-3%E5%AF%BE%E5%BF%9C-%E3%80%8C%E9%BB%92%E5%B8%AF%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%80%8D%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/479739580X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2L232G2DZ5DCE&dchild=1&keywords=%E5%9F%BA%E6%9C%AC%E3%81%8B%E3%82%89%E3%81%97%E3%81%A3%E3%81%8B%E3%82%8A%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%8Fandroid%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80&qid=1596870454&sprefix=%E5%9F%BA%E6%9C%AC%E3%81%8B%E3%82%89%E3%81%97%E3%81%A3%E3%81%8B%E3%82%8A%2Caps%2C236&sr=8-1)