Java tutorial
/* * ================================================================================================= * Copyright (C) 2013 - 2014 Martin Albedinsky [Wolf-ITechnologies] * ================================================================================================= * Licensed under the Apache License, Version 2.0 or later (further "License" only). * ------------------------------------------------------------------------------------------------- * You may use this file only in compliance with the License. More details and copy of this License * you may obtain at * * http://www.apache.org/licenses/LICENSE-2.0 * * You can redistribute, modify or publish any part of the code written within this file but as it * is described in the License, the software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF ANY KIND. * * See the License for the specific language governing permissions and limitations under the License. * ================================================================================================= */ package com.wit.android.preference; import android.content.SharedPreferences; import android.content.res.Resources; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.text.TextUtils; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; /** * <h3>Class Overview</h3> * todo: description * * @param <Type> A type of the value which this implementation of preference holds and manages its saving/obtaining. * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public abstract class SharedPreference<Type> { /** * Interface =================================================================================== */ /** * <h3>Interface Overview</h3> * todo: description * * @param <PreferenceType> Type of the preference, for which is this callback created. * @author Martin Albedinsky */ public static interface PreferenceChangeCallback<PreferenceType> { /** * Fired when the value of the passed <var>preference</var> was changed. The passed * preference already contains new value parsed from shared preferences. * * @param preference The preference, of which value was changed. */ public void onPreferenceChanged(SharedPreference<PreferenceType> preference); } /** * Constants =================================================================================== */ /** * Log TAG. */ // private static final String TAG = "SharedPreference"; /** * Flag indicating whether the debug output trough log-cat is enabled or not. */ // private static final boolean DEBUG_ENABLED = true; /** * Flag indicating whether the output trough log-cat is enabled or not. */ // private static final boolean LOG_ENABLED = true; /** * Static members ============================================================================== */ /** * Members ===================================================================================== */ /** * The key under which will be the value of this preference mapped within shared preferences. */ String mKey; /** * Default value of this preference for case, when there is no value saved withing * shared preference yet. */ Type mDefaultValue; /** * Actual value of this shared preference to save. */ Type mActualValue; /** * Xml resource */ private int mKeyRes = -1; /** * Flag indicating whether the {@link #mActualValue} is same as value saved within shared * preferences. */ private boolean mAlreadyParsed; /** * Constructors ================================================================================ */ /** * Creates a new instance of SharedPreference with the given key and default value. * * @param key The key under which will be the value of this preference mapped within * shared preferences. * @param defValue Default value of this preference to return in case, when there is no value * saved withing shared preference yet. * @see #setUpKey(android.content.res.Resources) */ protected SharedPreference(@NonNull String key, @Nullable Type defValue) { this.mKey = key; this.mDefaultValue = mActualValue = defValue; } /** * Creates a new instance of SharedPreference with the given key resource and default value. * * @param keyResId XXml resource of the key under which will be the value of this preference * mapped within shared preferences. * @param defaultValue Default value of this preference for case, when there is no value saved withing * shared preference yet. */ protected SharedPreference(@StringRes int keyResId, @Nullable Type defaultValue) { this.mKeyRes = keyResId; this.mDefaultValue = defaultValue; } /** * Methods ===================================================================================== */ /** * Public -------------------------------------------------------------------------------------- */ /** * Obtains the key for this preference from the given resources using the current key's xml resource * id passed to {@link #SharedPreference(int, Object)}. * * @param resources An application's resources to obtain key. * @return This preference. */ public SharedPreference<Type> setUpKey(@NonNull Resources resources) { this.obtainKeyFromResources(resources); return this; } /** * Parses the current value of this preference from shared preferences. * * @param manager The preferences manager which can provide the instance of shared preferences * into which was the value of this preference before saved. * @return This preference. * @see #parse(android.content.SharedPreferences) * @see #getActualValue() */ public SharedPreference<Type> parse(@NonNull PreferencesManager manager) { return parse(manager.getSharedPreferences()); } /** * Parses the current value of this preference from the given shared preferences. * * @param preferences The instance of shared preferences into which was the value of this preference * before saved. * @return This preference. * @see #parse(PreferencesManager) * @see #getActualValue() */ public SharedPreference<Type> parse(@NonNull SharedPreferences preferences) { this.mActualValue = performObtainFromPreferences(preferences); return this; } /** * Same as {@link #save(android.content.SharedPreferences)} where the instance of shared * preferences will be obtained from the given <var>manager</var>. * * @param manager The preferences manager which provides the instance of shared preferences into * which should be the current value of this preference saved. * @return {@code True} if saving operation succeed, {@code false} otherwise. * @see #save(android.content.SharedPreferences) * @see #updateValue(Object) */ public boolean save(@NonNull PreferencesManager manager) { return performPutIntoPreferences(manager.getSharedPreferences()); } /** * Saves the current value of this preference into the given shared preferences. * * @param preferences The instance of shared preferences into which will be the current value of * this preference saved. * @return {@code True} if saving operation succeed, {@code false} otherwise. * @see #save(PreferencesManager) * @see #updateValue(Object) */ public boolean save(@NonNull SharedPreferences preferences) { return performPutIntoPreferences(preferences); } /** * Creates new instance of {@link SharedPreferences.OnSharedPreferenceChangeListener} which can * be used to listen on changes provided up on the value of this preference within shared preferences. * <p> * <b>Note</b>, that here created listener will fire the given callback only in case, that the * key received in the callback from shared preferences will match the key of this preference. * * @param callback Callback to be invoked when the value of this preference changes. * @return New instance of OnSharedPreferenceListener. * @see android.content.SharedPreferences */ @NonNull public SharedPreferences.OnSharedPreferenceChangeListener createOnChangeListener( @NonNull final PreferenceChangeCallback<Type> callback) { return new SharedPreferences.OnSharedPreferenceChangeListener() { /** */ @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (mKey.equals(key)) { // Parse actual value. parse(sharedPreferences); // Invoke callback. callback.onPreferenceChanged(SharedPreference.this); } } }; } /** * Getters + Setters --------------------------------------------------------------------------- */ /** * Returns the key of this preference. * * @return Same key as passed to {@link #SharedPreference(String, Object)}. */ @NonNull public final String getKey() { return mKey; } /** * Returns the default value of this preference. * * @return Same value as passed to {@link #SharedPreference(String, Object)}. */ public final Type getDefaultValue() { return mDefaultValue; } /** * Returns the value, which is currently being hold by this preference object. <b>Note</b>, that * this isn't current value from shared preferences if this preference wasn't parsed * ({@link #parse(PreferencesManager)} or {@link #parse(android.content.SharedPreferences)}) * before this call. * <p> * To obtain always an actual value from shared preferences, perform this calls on the instance * of SharedPreference of which value you want to obtain: * <pre> * {@code <b>SharedPreference.parse(SharedPreferences).getActualValue()</b>} or * {@code <b>SharedPreference.parse(PreferencesManager).getActualValue()</b>} * </pre> * * @return The actual value of this preference or {@code null} if this preference's key is * invalid. * @see #parse(PreferencesManager) * @see #parse(android.content.SharedPreferences) */ public final Type getActualValue() { return mActualValue; } /** * Updates the actual value of this preference to the given one. <b>Note</b>, that * this doesn't updates the value within shared preferences. * <p> * To immediately save the given new value of this preference into shared preferences, perform * this calls on the instance of SharedPreference of which value you want to save: * <pre> * {@code <b>SharedPreference.updateValue(Type).save(SharedPreferences)</b>} or * {@code <b>SharedPreference.updateValue(Type).save(PreferencesManager)</b>} * </pre> * * @param newValue New value for this preference. * @return This preference. * @see #save(PreferencesManager) * @see #save(android.content.SharedPreferences) */ public SharedPreference<Type> updateValue(@Nullable Type newValue) { this.mAlreadyParsed = mActualValue != null && mActualValue.equals(newValue); this.mActualValue = newValue; return this; } /** * Protected ----------------------------------------------------------------------------------- */ /** * Performs saving of the actual value of this preference into the given shared preferences. * * @param preferences The instance of shared preferences into which should be the current value of * this preference saved. * @return {@code True} if saving operation succeed, {@code false} otherwise. */ final boolean performPutIntoPreferences(SharedPreferences preferences) { return mAlreadyParsed = (mKey != null && !mKey.equals("") && onPutIntoPreferences(preferences)); } /** * Invoked to save the actual value into the given shared preferences. * * @param preferences The instance of shared preferences into which should be the current value of * this preference saved. * @return {@code True} if saving operation succeed, {@code false} otherwise. */ protected abstract boolean onPutIntoPreferences(@NonNull SharedPreferences preferences); /** * Performs obtaining of the actual value of this preference from the given shared preferences. * * @param preferences The instance of shared preferences into which was the value of this preference * before saved. * @return The actual value obtained from the given shared preferences or {@code null} if this * preference's key is invalid. */ final Type performObtainFromPreferences(SharedPreferences preferences) { Type value = null; if (mAlreadyParsed) { value = mActualValue; } else if (mKey != null && !mKey.equals("")) { value = onObtainFromPreferences(preferences); this.mAlreadyParsed = true; } return value; } /** * Invoked to obtain the actual value of this preference from the given shared preferences. * * @param preferences The instance of shared preferences into which was the value of this preference * before saved. * @return The actual value of this preference from the given shared preferences. */ @Nullable protected abstract Type onObtainFromPreferences(@NonNull SharedPreferences preferences); /** * Clears the actual value of this preference. */ final void clear() { this.mActualValue = null; this.mAlreadyParsed = false; } /** * Private ------------------------------------------------------------------------------------- */ /** * If the current <var>mKeyRes</var> is valid resource, this will obtain the string value of this * key's resource from the given resources. * * @param resources An application's resources to obtain key. */ private void obtainKeyFromResources(Resources resources) { if (mKey == null && mKeyRes > 0) { this.mKey = resources.getString(mKeyRes); } } /** * Inner classes =============================================================================== */ /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.lang.String} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class StringPreference extends SharedPreference<String> { /** * Constructors ============================================================================ */ /** * Creates a new instance of StringPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public StringPreference(@NonNull String key, @Nullable String defValue) { super(key, defValue); } /** * Creates a new instance of StringPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public StringPreference(@StringRes int keyResId, @Nullable String defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return preferences.edit().putString(mKey, mActualValue).commit(); } /** */ @Nullable @Override protected String onObtainFromPreferences(@NonNull SharedPreferences preferences) { return preferences.getString(mKey, mDefaultValue); } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.lang.Boolean} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class BooleanPreference extends SharedPreference<Boolean> { /** * Constructors ============================================================================ */ /** * Creates a new instance of BooleanPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public BooleanPreference(@NonNull String key, @NonNull Boolean defValue) { super(key, defValue); } /** * Creates a new instance of BooleanPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public BooleanPreference(@StringRes int keyResId, @NonNull Boolean defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return preferences.edit().putBoolean(mKey, mActualValue).commit(); } /** */ @Nullable @Override protected Boolean onObtainFromPreferences(@NonNull SharedPreferences preferences) { return preferences.getBoolean(mKey, mDefaultValue); } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.lang.Integer} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class IntegerPreference extends SharedPreference<Integer> { /** * Constructors ============================================================================ */ /** * Creates a new instance of IntegerPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public IntegerPreference(@NonNull String key, @NonNull Integer defValue) { super(key, defValue); } /** * Creates a new instance of IntegerPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public IntegerPreference(@StringRes int keyResId, @NonNull Integer defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return preferences.edit().putInt(mKey, mActualValue).commit(); } /** */ @Nullable @Override protected Integer onObtainFromPreferences(@NonNull SharedPreferences preferences) { return preferences.getInt(mKey, mDefaultValue); } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.lang.Float} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class FloatPreference extends SharedPreference<Float> { /** * Constructors ============================================================================ */ /** * Creates a new instance of FloatPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public FloatPreference(@NonNull String key, @NonNull Float defValue) { super(key, defValue); } /** * Creates a new instance of FloatPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public FloatPreference(@StringRes int keyResId, @NonNull Float defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return preferences.edit().putFloat(mKey, mActualValue).commit(); } /** */ @Nullable @Override protected Float onObtainFromPreferences(@NonNull SharedPreferences preferences) { return preferences.getFloat(mKey, mDefaultValue); } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.lang.Long} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class LongPreference extends SharedPreference<Long> { /** * Constructors ============================================================================ */ /** * Creates a new instance of LongPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public LongPreference(@NonNull String key, @NonNull Long defValue) { super(key, defValue); } /** * Creates a new instance of LongPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public LongPreference(@StringRes int keyResId, @NonNull Long defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return preferences.edit().putLong(mKey, mActualValue).commit(); } /** */ @Nullable @Override protected Long onObtainFromPreferences(@NonNull SharedPreferences preferences) { return preferences.getLong(mKey, mDefaultValue); } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.lang.Enum} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @param <E> A type of the enum implementation of which value will this preference manage. * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class EnumPreference<E extends Enum> extends SharedPreference<E> { /** * Constructors ============================================================================ */ /** * Creates a new instance of EnumPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public EnumPreference(@NonNull String key, @Nullable E defValue) { super(key, defValue); } /** * Creates a new instance of EnumPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public EnumPreference(@StringRes int keyResId, @Nullable E defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return preferences.edit().putString(mKey, mActualValue.name()).commit(); } /** */ @Nullable @Override @SuppressWarnings("unchecked") protected E onObtainFromPreferences(@NonNull SharedPreferences preferences) { final String enumName = preferences.getString(mKey, mDefaultValue.name()); return (E) E.valueOf(mDefaultValue.getClass(), enumName); } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of <b>array</b> within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @param <A> A type of the array of which value will this preference manage. * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.EnumPreference * @see com.wit.android.preference.SharedPreference.ListPreference */ public static final class ArrayPreference<A> extends SharedPreference<A> { /** * Constants =============================================================================== */ /** * Log TAG. */ private static final String TAG = "ArrayPreference"; /** * Constructors ============================================================================ */ /** * Creates a new instance of ArrayPreference. * * @throws java.lang.IllegalArgumentException If the given <var>defValue</var> is not actually * an array. * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public ArrayPreference(@NonNull String key, @Nullable A defValue) { super(key, defValue); // Only array object is allowed. if (defValue != null && !defValue.getClass().isArray()) { throw new IllegalArgumentException("Not an array (" + defValue.getClass().getSimpleName() + ")."); } } /** * Creates a new instance of ArrayPreference. * * @throws java.lang.IllegalArgumentException If the given <var>defValue</var> is not actually * an array. * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public ArrayPreference(@StringRes int keyResId, @Nullable A defValue) { super(keyResId, defValue); // Only array object is allowed. if (defValue != null && !defValue.getClass().isArray()) { throw new IllegalArgumentException("Not an array (" + defValue.getClass().getSimpleName() + ")."); } } /** * Methods ================================================================================= */ /** * Saves the given <var>array</var> into the given shared <var>preferences</var>. * * @param preferences The instance of shared preferences into which will be the given array saved. * @param key The key under which will be the saved array mapped in the shared preferences. * @param array Array to save into preferences. * @return {@code True} if saving succeeded, {@code false} otherwise. * @throws java.lang.IllegalArgumentException If the given <var>array</var> is not actually an array. */ public static boolean putIntoPreferences(@NonNull SharedPreferences preferences, @NonNull String key, @Nullable Object array) { if (array == null) { return preferences.edit().putString(key, null).commit(); } // Only array object is allowed. if (!array.getClass().isArray()) { throw new IllegalArgumentException("Not an array (" + array.getClass().getSimpleName() + ")."); } final int n = Array.getLength(array); final JSONArray jsonArray = new JSONArray(); for (int i = 0; i < n; i++) { jsonArray.put(Array.get(array, i)); } // Save also class of array, so when obtaining array we will know exactly of which type it is. final Class<?> classOfArray = resolveArrayClass(array); if (classOfArray == null) { throw new IllegalArgumentException("Failed to save array of('" + array.getClass() + "')." + "Can only save array of primitive types or theirs boxed representations, Object or String array."); } return preferences.edit().putString(key, classOfArray.getSimpleName() + ":" + jsonArray.toString()) .commit(); } /** * Returns an <b>array</b> mapped in the given shared <var>preferences</var> under the * specified <var>key</var>. * * @param preferences The instance of shared preferences into which was the requested array * before saved. * @param key The key under which is the saved list mapped in the shared preferences. * @param defValue Default array to return if there is no mapping for the specified <var>key</var> * yet. * @param <A> The type of an array to obtain. * @return An instance of the requested array or <var>defValue</var> if there is no mapping * for the specified key. */ @SuppressWarnings("unchecked") public static <A> A obtainFromPreferences(@NonNull SharedPreferences preferences, @NonNull String key, @Nullable Object defValue) { Object array = defValue; final String arrayAsString = preferences.getString(key, null); if (!TextUtils.isEmpty(arrayAsString)) { final String[] parts = arrayAsString.split(":"); if (parts.length > 1) { final Class<?> classOfArray = resolveArrayClassByName(parts[0]); if (classOfArray != null) { JSONArray jsonArray; try { jsonArray = new JSONArray(parts[1]); } catch (JSONException ignored) { Log.e(TAG, "Failed to obtain array for key(" + key + ") from shared preferences."); return (A) defValue; } final int n = jsonArray.length(); array = resolveArrayForClass(classOfArray, n); // Fill the resolved array. for (int i = 0; i < n; i++) { Array.set(array, i, jsonArray.opt(i)); } } else { Log.e(TAG, "Unknown class('" + parts[0] + "') of array."); } } else { throw new IllegalStateException( "Trying to obtain an array not saved by this preferences framework."); } } return (A) array; } /** * @see #putIntoPreferences(android.content.SharedPreferences, String, Object) */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return putIntoPreferences(preferences, mKey, mActualValue); } /** * @see #obtainFromPreferences(android.content.SharedPreferences, String, Object) */ @Nullable @Override @SuppressWarnings("unchecked") protected A onObtainFromPreferences(@NonNull SharedPreferences preferences) { return obtainFromPreferences(preferences, mKey, mDefaultValue); } /** * Returns class of an items presented within the given <var>array</var>. * * @param array The array of which class should be resolved. * @return Class of an items within the given array or {@code null} if the given array * does not matches supported array types. */ static Class<?> resolveArrayClass(Object array) { if (array instanceof boolean[]) { return boolean.class; } else if (array instanceof byte[]) { return byte.class; } else if (array instanceof char[]) { return char.class; } else if (array instanceof short[]) { return short.class; } else if (array instanceof int[]) { return int.class; } else if (array instanceof float[]) { return float.class; } else if (array instanceof long[]) { return long.class; } else if (array instanceof double[]) { return double.class; } else if (array instanceof Boolean[]) { return Boolean.class; } else if (array instanceof Byte[]) { return Byte.class; } else if (array instanceof Short[]) { return Short.class; } else if (array instanceof Integer[]) { return Integer.class; } else if (array instanceof Float[]) { return Float.class; } else if (array instanceof Long[]) { return Long.class; } else if (array instanceof Double[]) { return Double.class; } else if (array instanceof String[]) { return String.class; } else if (array instanceof Object[]) { return Object.class; } return null; } /** * Returns class for the requested <var>arrayClassName</var>. * * @param arrayClassName Name of the class for which is its name requested. * @return Name of the requested class or {@code Object.class} if the given name does * not matches the supported types. */ static Class<?> resolveArrayClassByName(String arrayClassName) { switch (arrayClassName) { case "boolean": return boolean.class; case "byte": return byte.class; case "char": return char.class; case "short": return short.class; case "int": return int.class; case "float": return float.class; case "long": return long.class; case "double": return double.class; case "Boolean": return Boolean.class; case "Byte": return Byte.class; case "Short": return Short.class; case "Integer": return Integer.class; case "Float": return Float.class; case "Long": return Long.class; case "Double": return Double.class; case "String": return String.class; } return Object.class; } /** * Creates a new instance of array of the requested <var>arrayClass</var> type. * * @param arrayClass Class of array to create. * @param size Size of array. * @return New instance of array type of the requested class. */ static Object resolveArrayForClass(Class<?> arrayClass, int size) { if (boolean.class.equals(arrayClass)) { return new boolean[size]; } else if (byte.class.equals(arrayClass)) { return new byte[size]; } else if (char.class.equals(arrayClass)) { return new char[size]; } else if (short.class.equals(arrayClass)) { return new short[size]; } else if (int.class.equals(arrayClass)) { return new int[size]; } else if (float.class.equals(arrayClass)) { return new float[size]; } else if (long.class.equals(arrayClass)) { return new long[size]; } else if (double.class.equals(arrayClass)) { return new double[size]; } else if (Boolean.class.equals(arrayClass)) { return new Boolean[size]; } else if (Byte.class.equals(arrayClass)) { return new Byte[size]; } else if (Short.class.equals(arrayClass)) { return new Short[size]; } else if (Integer.class.equals(arrayClass)) { return new Integer[size]; } else if (Float.class.equals(arrayClass)) { return new Float[size]; } else if (Long.class.equals(arrayClass)) { return new Long[size]; } else if (Double.class.equals(arrayClass)) { return new Double[size]; } else if (String.class.equals(arrayClass)) { return new String[size]; } return new Object[size]; } } /** * <h3>Class Overview</h3> * Shared preference which can manage value of {@link java.util.List} within {@link SharedPreferences}. * See also other implementations of {@link SharedPreference} for different types which * can be saved/obtained into/from shared preferences. * * @param <T> A type of an items which are presented within List of which value will this * preference manage. * @author Martin Albedinsky * @see com.wit.android.preference.SharedPreference.BooleanPreference * @see com.wit.android.preference.SharedPreference.IntegerPreference * @see com.wit.android.preference.SharedPreference.LongPreference * @see com.wit.android.preference.SharedPreference.StringPreference * @see com.wit.android.preference.SharedPreference.FloatPreference * @see com.wit.android.preference.SharedPreference.EnumPreference */ public static final class ListPreference<T> extends SharedPreference<List<T>> { /** * Constructors ============================================================================ */ /** * Creates a new instance of ListPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(String, Object) */ public ListPreference(@NonNull String key, @Nullable List<T> defValue) { super(key, defValue); } /** * Creates a new instance of ListPreference. * * @see com.wit.android.preference.SharedPreference#SharedPreference(int, Object) */ public ListPreference(@StringRes int keyResId, @Nullable List<T> defValue) { super(keyResId, defValue); } /** * Methods ================================================================================= */ /** * Saves the given <var>list</var> into the given shared <var>preferences</var>. * * @param preferences The instance of shared preferences into which will be the given list saved. * @param key The key under which will be the saved list mapped in the shared preferences. * @param list List to save into preferences. * @param <T> Type of an items which are presented within the given list. * @return {@code True} if saving succeeded, {@code false} otherwise. */ public static <T> boolean putIntoPreferences(@NonNull SharedPreferences preferences, @NonNull String key, @Nullable List<T> list) { return preferences.edit().putString(key, new JSONArray(list).toString()).commit(); } /** * Returns a {@link java.util.List} mapped in the given shared <var>preferences</var> under * the specified <var>key</var>. * * @param preferences The instance of shared preferences into which was the requested list * before saved. * @param key The key under which is the saved list mapped in the shared preferences. * @param defValue Default list to return if there is no mapping for the specified <var>key</var> * yet. * @param <T> Type of an items which should be presented within the obtained list. * @return An instance of the requested list or <var>defValue</var> if there is no mapping * for the specified key. */ @SuppressWarnings("unchecked") public static <T> List<T> obtainFromPreferences(@NonNull SharedPreferences preferences, @NonNull String key, @Nullable List<T> defValue) { List<T> list = defValue; final String jsonArray = preferences.getString(key, null); if (jsonArray != null) { try { final JSONArray array = new JSONArray(jsonArray); final int n = array.length(); list = new ArrayList<>(n); for (int i = 0; i < n; i++) { list.add((T) array.get(i)); } } catch (JSONException e) { e.printStackTrace(); } } return list; } /** * @see #putIntoPreferences(android.content.SharedPreferences, String, java.util.List) */ @Override protected boolean onPutIntoPreferences(@NonNull SharedPreferences preferences) { return putIntoPreferences(preferences, mKey, mActualValue); } /** * @see #obtainFromPreferences(android.content.SharedPreferences, String, java.util.List) */ @Nullable @Override protected List<T> onObtainFromPreferences(@NonNull SharedPreferences preferences) { return obtainFromPreferences(preferences, mKey, mDefaultValue); } } }