22

I want to save/recall an integer array using SharedPreferences. Is this possible?

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
user878813
  • 785
  • 2
  • 16
  • 28

8 Answers8

57

You can try to do it this way:

  • Put your integers into a string, delimiting every int by a character, for example a comma, and then save them as a string:

    SharedPreferences prefs = getPreferences(MODE_PRIVATE);
    int[] list = new int[10];
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < list.length; i++) {
        str.append(list[i]).append(",");
    }
    prefs.edit().putString("string", str.toString());
    
  • Get the string and parse it using StringTokenizer:

    String savedString = prefs.getString("string", "");
    StringTokenizer st = new StringTokenizer(savedString, ",");
    int[] savedList = new int[10];
    for (int i = 0; i < 10; i++) {
        savedList[i] = Integer.parseInt(st.nextToken());
    }
    
Adrian Toman
  • 11,316
  • 5
  • 48
  • 62
Egor
  • 39,695
  • 10
  • 113
  • 130
  • 1
    Note that this method could be used only when you have little amount of data, since String operations aren't efficient. (every character needs to be parsed when reading). – Paweł Brewczynski Jan 05 '14 at 13:43
  • 4
    According to the javadoc, the use of StringTokenizer is discouraged: http://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html, use String.split() instead. See here http://stackoverflow.com/questions/6983856/why-is-stringtokenizer-deprecated – Julio_oa Apr 23 '14 at 14:38
14

You can't put Arrays in SharedPreferences, but you can workaround:

private static final String LEN_PREFIX = "Count_";
private static final String VAL_PREFIX = "IntValue_";
public void storeIntArray(String name, int[] array){
    SharedPreferences.Editor edit= mContext.getSharedPreferences("NAME", Context.MODE_PRIVATE).edit();
    edit.putInt(LEN_PREFIX + name, array.length);
    int count = 0;
    for (int i: array){
        edit.putInt(VAL_PREFIX + name + count++, i);
    }
    edit.commit();
}
public int[] getFromPrefs(String name){
    int[] ret;
    SharedPreferences prefs = mContext.getSharedPreferences("NAME", Context.MODE_PRIVATE);
    int count = prefs.getInt(LEN_PREFIX + name, 0);
    ret = new int[count];
    for (int i = 0; i < count; i++){
        ret[i] = prefs.getInt(VAL_PREFIX+ name + i, i);
    }
    return ret;
}
Rafael T
  • 15,401
  • 15
  • 83
  • 144
5

Here's my version, based on Egor's answer. I prefer not to use StringBuilder unless I'm building an enourmous string, but thanks to Egor for using StringTokenizer -- haven't made much use of this in the past, but it's very handy! FYI, this went in my Utility class:

public static void saveIntListPrefs(
    String name, Activity activity, List<Integer> list)
{
  String s = "";
  for (Integer i : list) {
    s += i + ",";
  }

  Editor editor = activity.getPreferences(Context.MODE_PRIVATE).edit();
  editor.putString(name, s);
  editor.commit();
}

public static ArrayList<Integer> readIntArrayPrefs(String name, Activity activity)
{
  SharedPreferences prefs = activity.getPreferences(Context.MODE_PRIVATE);
  String s = prefs.getString(name, "");
  StringTokenizer st = new StringTokenizer(s, ",");
  ArrayList<Integer> result = new ArrayList<Integer>();
  while (st.hasMoreTokens()) {
    result.add(Integer.parseInt(st.nextToken()));
  }
  return result;
}
Nick Bolton
  • 38,276
  • 70
  • 174
  • 242
5

Two solutions:

(1) Use http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html

It has split/join functions that let you join and split the integers in one liners:

StringUtils.join([1, 2, 3], ';')  = "1;2;3"
StringUtils.split("1;2;3", ';')   = ["1", "2", "3"]

You'd still have to convert the strings back to integers, though.

Actually, for splitting java.lang.String.split() will work just as fine: http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String)

(2) Use the SharedPreferences.putStringSet() (API 11):

    SharedPreferences.Editor editor = preferences.edit();
    int count = this.intSet.size();
    if (count > 0) {
        Set<String> theSet = new HashSet<String>();
        for (Long l : this.intSet) {
            theSet.add(String.valueOf(l));
        }
        editor.putStringSet(PREFS_KEY, theSet);
    } else {
        editor.remove(PREFS_KEY);
    }
    editor.commit();

And to get it back:

    Set<String> theSet = this.preferences.getStringSet(PREFS_KEY, null);
    if (theSet != null && !theSet.isEmpty()) {
        this.intSet.clear();
        for (String s : theSet) {
            this.intSet.add(Integer.valueOf(s));
        }
    }

This code does not catch the NPEs or NumberFormatExceptions because the intSet is otherwise assured to not contain any nulls. But of course, if you cannot assure that in your code you should surround this with a try/catch.

Risadinha
  • 16,058
  • 2
  • 88
  • 91
4

I like to use JSON, which can be stored and retrieved as a string, to represent any complex data in SharedPreferences. So, in the case of an int array:

public void setPrefIntArray(String tag, int[] value)
{
    SharedPreferences.Editor prefEditor = PreferenceManager.getDefaultSharedPreferences(context)
            .edit();

    String s;
    try
    {
        JSONArray jsonArr = new JSONArray();
        for (int i : value)
            jsonArr.put(i);

        JSONObject json = new JSONObject();
        json.put(tag, jsonArr);

        s = json.toString();
    }
    catch(JSONException excp)
    {
        s = "";
    }

    prefEditor.putString(tag, s);
    prefEditor.commit();
}

public int[] getPrefIntArray(String tag, int[] defaultValue)
{
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);

    String s = pref.getString(tag, "");

    try
    {
        JSONObject json = new JSONObject(new JSONTokener(s));
        JSONArray jsonArr = json.getJSONArray(tag);

        int[] result = new int[jsonArr.length()];

        for (int i = 0; i < jsonArr.length(); i++)
            result[i] = jsonArr.getInt(i);

        return result;
    }
    catch(JSONException excp)
    {
        return defaultValue;
    }
}

The beauty is that the same idea can be applied to any other complex data representable as a JSON.

GozzoMan
  • 782
  • 9
  • 23
  • 1
    This is by far the best and most versatile solution. You can make these methods static (just pass context or the SharedPreferences / Editor to the function) and put ir in a Utils class to use it anywhere. – Luís Henriques Jul 02 '21 at 12:19
2

Here is how the "convert to comma-separated String" solution could look in Kotlin, implemented as extension functions:

fun SharedPreferences.Editor.putIntArray(key: String, value: IntArray): SharedPreferences.Editor {
    return putString(key, value.joinToString(
            separator = ",", 
            transform = { it.toString() }))
}

fun SharedPreferences.getIntArray(key: String): IntArray {
    with(getString(key, "")) {
        with(if(isNotEmpty()) split(',') else return intArrayOf()) {
            return IntArray(count(), { this[it].toInt() })
        }
    }
}

That way you can use putIntArray(String, IntArray) and getIntArray(String) just like the other put and set methods:

val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
prefs.edit().putIntArray(INT_ARRAY_TEST_KEY, intArrayOf(1, 2, 3)).apply()
val intArray = prefs.getIntArray(INT_ARRAY_TEST_KEY)
Michael Geier
  • 1,653
  • 1
  • 16
  • 18
0

I went for the below solution, it's the least verbose of what I could see in this thread (in my case I wanted to have a set as a collection). "value" is the of type Set<Int>.

Save:

sharedPreferences.edit {
    if (value.isNotEmpty()) {
        putStringSet(key, hashSetOf(*value.map { it.toString() }.toTypedArray()))
    } else {
        remove(key)
    }
}

Retrieve:

val stringSet = sharedPreferences.getStringSet(key, null)
if (stringSet.isNullOrEmpty()) return emptySet()

return setOf<Int>(*stringSet.map { Integer.valueOf(it) }.toTypedArray())
Mieszko Koźma
  • 460
  • 4
  • 10
-1

You can only save primitive values in sharedPreference. Use Sqlite instead.

Adrian Toman
  • 11,316
  • 5
  • 48
  • 62
Vineet Shukla
  • 23,865
  • 10
  • 55
  • 63