Как я могу сохранить целочисленный массив в SharedPreferences?

Я хочу сохранить/вызвать целочисленный массив с помощью SharedPreferences, возможно ли это?


person user878813    schedule 24.08.2011    source источник


Ответы (7)


Вы можете попробовать сделать это следующим образом:

  • Поместите свои целые числа в строку, разделяя каждое целое символом, например, запятой, а затем сохраните их как строку:

    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());
    
  • Получите строку и проанализируйте ее с помощью 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());
    }
    
person Egor    schedule 24.08.2011
comment
Обратите внимание, что этот метод можно использовать только при небольшом объеме данных, поскольку операции со строками неэффективны. (каждый символ должен быть проанализирован при чтении). - person Paul Brewczynski; 05.01.2014
comment
Согласно javadoc, использование StringTokenizer не рекомендуется: docs.oracle.com/javase/7/docs/api/java/util/ вместо этого используйте String.split(). См. здесь stackoverflow.com/questions/6983856/ - person Julio_oa; 23.04.2014

Вы не можете поместить массивы в SharedPreferences, но вы можете обойти это:

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;
}
person Rafael T    schedule 24.08.2011

Вот моя версия, основанная на ответе Егора. Я предпочитаю не использовать StringBuilder, если только я не создаю огромную строку, но спасибо Егору за использование StringTokenizer — раньше я не очень им пользовался, но он очень удобен! К вашему сведению, это было в моем классе Utility:

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;
}
person Nick Bolton    schedule 26.06.2012
comment
Цикл for должен использовать класс StringBuilder и не иметь такой конкатенации строк. - person Anthony; 07.04.2018

Два решения:

(1) Используйте http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html

Он имеет функции разделения/объединения, которые позволяют объединять и разделять целые числа в одном лайнере:

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

Однако вам все равно придется преобразовать строки обратно в целые числа.

На самом деле, для разделения java.lang.String.split() будет работать так же хорошо: http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String)

(2) Используйте 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();

И чтобы вернуть:

    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));
        }
    }

Этот код не перехватывает NPE или исключения NumberFormatException, потому что в противном случае intSet не содержит пустых значений. Но, конечно, если вы не можете гарантировать это в своем коде, вы должны окружить это с помощью try/catch.

person Risadinha    schedule 09.07.2014
comment
Решение 2 - это путь - person Cobbles; 27.10.2014
comment
Второе решение хорошее, но оно потеряет порядок элементов. - person blackwolf; 04.08.2015
comment
@blackwolf Попробуйте это с java.util.SortedSet - возможно, Android правильно его сериализует. - person Risadinha; 04.08.2015
comment
«SharedPreferences» используют «HashSets». См. CommonsWare ответ - person blackwolf; 04.08.2015

Мне нравится использовать JSON, который можно хранить и извлекать в виде строки, для представления любых сложных данных в SharedPreferences. Итак, в случае массива int:

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;
    }
}

Прелесть в том, что ту же идею можно применить к любым другим сложным данным, представляемым в виде JSON.

person GozzoMan    schedule 30.08.2017
comment
Это, безусловно, лучшее и универсальное решение. Вы можете сделать эти методы статическими (просто передать контекст или SharedPreferences/Editor в функцию) и поместить ir в класс Utils, чтобы использовать его где угодно. - person Luís Henriques; 02.07.2021

Вы можете сохранять только примитивные значения в sharedPreference. Вместо этого используйте Sqlite.

person Vineet Shukla    schedule 24.08.2011

Вот как может выглядеть решение «преобразовать в строку с разделителями-запятыми» в Kotlin, реализованное как функции расширения:

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() })
        }
    }
}

Таким образом, вы можете использовать putIntArray(String, IntArray) и getIntArray(String) так же, как и другие методы put и set:

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)
person Michael Geier    schedule 05.11.2017