Android SharedPreferencesでClassCastExceptionと、一つのkeyに二つの型を保存できるのか?を調べる

SharedPreferences を使った記事の続き。

前回の記事↓

SharedPreferences
まだ調べ足りないことがあったので
2点ほど調査する。

 

保存した型と違う型を取得

そりゃダメだよねって明らかに分かる
違う型を取得するパターンだが、一応記載。

下記の実装では
String で保存したのに
boolean を取得しようとしている。

取得時 ClassCastException が吐き出される

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean

PreferenceUtil.java

public class PreferenceUtil {

    enum PreferenceKey {
        KEY_STRING,
        KEY_BOOLEAN,
    }

    // Stringを保存
    public static void putString(Context context, PreferenceKey key, String value) {
        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = pref.edit();
        editor.putString(key.name(), value);
        editor.apply();
    }

    // booleanを保存
    public static void putBoolean(Context context, PreferenceKey key, boolean value) {
        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
        editor.putBoolean(key.name(), value);
        editor.apply();
    }

    // Stringを取得
    public static String getString(Context context, PreferenceKey key) {
        return PreferenceManager.getDefaultSharedPreferences(context)
                .getString(key.name(), "");
    }

    // booleanを取得
    public static boolean getBoolean(Context context, PreferenceKey key) {
        return PreferenceManager.getDefaultSharedPreferences(context)
                .getBoolean(key.name(), false);
    }

}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // KEY_STRINGで適当な文字列を保存する
        PreferenceUtil.putString(getApplicationContext(),
                PreferenceUtil.PreferenceKey.KEY_STRING, "文字列を保存");

        Button button = findViewById(R.id.button);
        button.setOnClickListener(view -> {

            // KEY_STRINGでbooleanを取得しようとするが
            // 保存した値の型が違うのでgetできない
            boolean bool = PreferenceUtil.getBoolean(
                    getApplicationContext(), PreferenceUtil.PreferenceKey.KEY_STRING);
            Toast.makeText(this, "Boolean:" + bool, Toast.LENGTH_LONG).show();
        });
    }
}

 

1つのkeyに2つの型を保存できる?

 

結論

結論から言うと
2つの型を同時に持つことはできない。

KEY_BOOLEAN という key があった時
KEY_BOOLEANboolean を保存
KEY_BOOLEANString を保存
の順序で処理すると
KEY_BOOLEAN で取得できるのは String となる

つまり
最後に処理した型が保存される
(後勝ちで上書かれる)

 

検証

先ほどの PreferenceUtilクラス はそのままで
MainActivity の処理を変えて検証してみる。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ① KEY_BOOLEANにbooleanを保存する
        PreferenceUtil.putBoolean(getApplicationContext(),
                PreferenceUtil.PreferenceKey.KEY_BOOLEAN, true);

        // ② KEY_BOOLEANにStringを保存する
        PreferenceUtil.putString(getApplicationContext(),
                PreferenceUtil.PreferenceKey.KEY_BOOLEAN, "keyにbooleanってあるけどいいの?");

        Button button = findViewById(R.id.button);
        button.setOnClickListener(view -> {
            /*
            // 最後に保存したのがStringなのでClassCastExceptionになる
            boolean bool = PreferenceUtil.getBoolean(
                    getApplicationContext(), PreferenceUtil.PreferenceKey.KEY_BOOLEAN);
             */

            // Stringは問題なく取得できる
            String str = PreferenceUtil.getString(
                    getApplicationContext(), PreferenceUtil.PreferenceKey.KEY_BOOLEAN);
            Toast.makeText(this, str, Toast.LENGTH_LONG).show();
        });
    }
}

①で保存した型である boolean
String に上書きされていることが分かる。

 

まとめ

一つの key に2つの型を保存
という行為そのものをしたことがなかったので
いい勉強になった。

もっと便利に使うなら
オブジェクトを json にして保存ができるから
今度はそこらへんをまとめてみよう。

開発日記

Posted by konp