これはAndroidその2 Advent Calendar 2016 12/20の投稿です。
はじめに
今回はキーと値のペアを保存、取得することができるSharedPreferences
をより安全、簡単に使うためにラッパークラスを作る話をします。
基本的な話となるため、SharedPreferences
の使用における自分なりのプラクティスが無い人向けの投稿となります。
ご了承ください。
基本的なSharedPreferences
使用法の再確認
標準的なSharedPreferences
を使用した値の書き込み、及び読み出しは以下のコードとなるかと思われます。
SharedPreferences sp = context.getSharedPreferences("hoge", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("fuga", false);
editor.apply();
SharedPreferences sp = context.getSharedPreferences("hoge", Context.MODE_PRIVATE);
boolean fuga = sp.getBoolean("fuga", false);
問題点
上記コードから問題点を洗い出してみます。
-
getSharedPreferences
,putBoolean
,getBoolean
メソッドの第一引数を忘れたり、スペルミスしたりしてしまう可能性がある。 -
apply
メソッドを呼び忘れる可能性がある。 - 全体的にもっとスマートに記述したい。
とりあえずはこのくらいでしょうか。
早速問題解決していきましょう。
実践
データファイルをenum管理
まずSharedPreferences
のデータファイルをenumで管理します。
public enum PreferenceNames {
DEFAULT("default");
HOGE("hoge");
private final String name;
PreferenceNames(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
データファイルを増やしたい場合は、このenumに追加するだけです。
簡単ですね。
SharedPreferences
のラッパークラスを作成する
次に、上記enumを取り扱うことが出来るようにSharedPreferences
のラッパークラスを作成し、コンストラクタを記述します。
public class MySharedPref{
private final SharedPreferences sp;
private final PreferenceNames preferenceNames;
public MySharedPref(Context context, PreferenceNames preferenceNames) {
if (preferenceNames == PreferenceNames.DEFAULT) {
this.sp = PreferenceManager.getDefaultSharedPreferences(context);
} else {
this.sp = context.getSharedPreferences(preferenceNames.getName(), Context.MODE_PRIVATE);
}
this.preferenceNames = preferenceNames;
}
}
ここでは、第二引数にPreferenceNames.DEFAULT
を設定した場合はgetDefaultSharedPreferences
メソッドをコールします。
これでgetSharedPreferences
メソッドの第一引数の忘れ、及びスペルミス問題は解決しました。
キーのenum管理
次に、キーをenumで管理します。
public enum PreferenceKeys {
FUGA(PreferenceNames.HOGE, Boolean.class, true);
private final PreferenceNames preferenceNames;
private final Class<?> valueClass;
private final String key;
PreferenceKeys(PreferenceNames preferenceNames, Class<?> valueClass, String key) {
this.preferenceNames = preferenceNames;
this.valueClass = valueClass;
this.key = key;
}
public PreferenceNames getPreferenceNames() {
return preferenceNames;
}
public Class<?> getValueClass() {
return valueClass;
}
public String getKey() {
return key;
}
}
SharedPreferences
のキーを増やしたい場合は、このenumに追加するだけです。
一列でそのキーが何のデータファイルで使用され、紐付けられる値のクラスは何かを把握することが出来るという点でもこのenumは優れています。
putXXX
メソッドの作成
putBoolean
メソッドを以下のように作成します。
public void putBoolean(PreferenceKeys preferenceKeys, boolean value) {
if (preferenceKeys.getPreferenceNames() == preferenceNames && preferenceKeys.getValueClass() == Boolean.class) {
sp.edit().putBoolean(preferenceKeys.getKey(), value).apply();
} else {
throw new IllegalArgumentException();
}
}
同時にapply
メソッドの呼び出し忘れ問題も解決することが出来ました。
一度にたくさんの値を保存する場合はまた別のソリューションを考える必要がありますが、値を一度に変更するような機能に関して、SharedPreferencesはあまり使用されないでしょう。
getXXX
メソッドの作成
getBoolean
メソッドは以下のように作成します。
public boolean getBoolean(PreferenceKeys preferenceKeys) {
if (preferenceKeys.getPreferenceNames() == preferenceNames && preferenceKeys.getValueClass() == Boolean.class) {
return sp.getBoolean(preferenceKeys.getKey(), false);
} else {
throw new IllegalArgumentException();
}
}
こちらも初期値を都度変更したい場合は、引数として渡してあげるといいでしょう。
そこら辺は人やプロジェクトによると思われるため、自由にカスタマイズしてみてください。
また、putXXX
, getXXX
メソッドはboolean以外にもStringやintなどが必要になるはずですので、同様に実装してみてください。
おまけ
ついでにclear
メソッドも作成してみましょう。
public void clear() {
sp.edit().clear().apply();
}
ラッパークラスとenumの作成は以上です。
比較
以下、ラッパークラスを使わないバージョンと使うバージョンでデータの書き込み、及び読み出しのサンプルを比較してみました。
// Use no wrapper
SharedPreferences sp = context.getSharedPreferences("hoge", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("fuga", false);
editor.apply();
// Use wrapper
MySharedPref sp = new MySharedPref(this, PreferenceNames.HOGE);
sp.putBoolean(PreferenceKeys.FUGA, true);
// Use no wrapper
SharedPreferences sp = context.getSharedPreferences("hoge", Context.MODE_PRIVATE);
boolean fuga = sp.getBoolean("fuga", false);
// Use wrapper
MySharedPref sp = new MySharedPref(getActivity(), PreferenceNames.HOGE);
boolean fuga = sp.getBoolean(PreferenceKeys.FUGA);
まとめ
さて、ラッパーを作る意義が感じられましたでしょうか。
今回は、基本的な機能しか実装していませんが、個人個人でカスタマイズして自分なりのSharedPreferencesラッパークラスを作成してみてください。