Можно ли добавить массив или объект в SharedPreferences на Android

83

У меня есть ArrayListобъект, у которого есть имя и указатель значка, и я хочу сохранить его в формате SharedPreferences. Как я могу сделать?

ПРИМЕЧАНИЕ: я не хочу использовать базу данных

zsniperx
источник

Ответы:

60

Итак, с сайта разработчика Android в хранилище данных :

Предпочтения пользователей

Общие предпочтения предназначены не только для сохранения «предпочтений пользователя», например того, какую мелодию звонка выбрал пользователь. Если вы заинтересованы в создании пользовательских настроек для вашего приложения, см. PreferenceActivity, который предоставляет платформу Activity для создания пользовательских настроек, которые будут автоматически сохраняться (с использованием общих настроек).

Так что я думаю, что это нормально, так как сохраняются просто пары ключ-значение.

Для оригинального плаката это не так уж и сложно. Вы просто просматриваете свой список массивов и добавляете элементы. В этом примере для простоты я использую карту, но вы можете использовать список массивов и соответствующим образом изменить его:

// my list of names, icon locations
Map<String, String> nameIcons = new HashMap<String, String>();
nameIcons.put("Noel", "/location/to/noel/icon.png");
nameIcons.put("Bob", "another/location/to/bob/icon.png");
nameIcons.put("another name", "last/location/icon.png");

SharedPreferences keyValues = getContext().getSharedPreferences("name_icons_list", Context.MODE_PRIVATE);
SharedPreferences.Editor keyValuesEditor = keyValues.edit();

for (String s : nameIcons.keySet()) {
    // use the name as the key, and the icon as the value
    keyValuesEditor.putString(s, nameIcons.get(s));
}
keyValuesEditor.commit()

Вы бы сделали что-то подобное, чтобы снова прочитать пары ключ-значение. Сообщите мне, если это сработает.

Обновление: если вы используете уровень API 11 или новее, существует метод записи набора строк.

Ноэль
источник
Спасибо, Ноэль, я разобрался с помощью вашего кода. Однако следите за опечатками в коде. ;)
zsniperx
Сработал как шарм ... Спасибо
Бала Вишну
74

Независимо от уровня API, проверьте массивы строк и массивы объектов в SharedPreferences


СОХРАНИТЬ МАССИВ

public boolean saveArray(String[] array, String arrayName, Context mContext) {   
    SharedPreferences prefs = mContext.getSharedPreferences("preferencename", 0);  
    SharedPreferences.Editor editor = prefs.edit();  
    editor.putInt(arrayName +"_size", array.length);  
    for(int i=0;i<array.length;i++)  
        editor.putString(arrayName + "_" + i, array[i]);  
    return editor.commit();  
} 

ЗАГРУЗИТЬ МАССИВ

public String[] loadArray(String arrayName, Context mContext) {  
    SharedPreferences prefs = mContext.getSharedPreferences("preferencename", 0);  
    int size = prefs.getInt(arrayName + "_size", 0);  
    String array[] = new String[size];  
    for(int i=0;i<size;i++)  
        array[i] = prefs.getString(arrayName + "_" + i, null);  
    return array;  
}  
Шериф Эль-Хатиб
источник
10
Это ужасная техника. См. Комментарии к этому блогу: «Проблема с этим подходом заключается в том, что вы загрязняете свои предпочтения. Скажем, вы сохраняете массив со 100 записями, а затем уменьшаете его до 2. У вас все равно будет 100 записей в ваших предпочтениях, если вы не сначала очисти его ".
Кайл Айви
2
Уборка - довольно простое дополнение
Sherif elKhatib
Спасибо, очень красивый стилизованный код. Это один из моих любимых ответов на SO. :)
Мартин Пфеффер
3
Это неправильный подход !!! вы пытаетесь добавить 100 переменных, и это ужасно !! вместо этого вы можете использовать этот метод с jsonarray и jsonbj: stackoverflow.com/a/8287418/2652368
Амир Хоссейн Гасеми,
@AmirHosseinGhasemi оба подхода на самом деле являются взломами. спасибо
Sherif elKhatib
60

Написать,

SharedPreferences prefs = PreferenceManager
        .getDefaultSharedPreferences(this);
JSONArray jsonArray = new JSONArray();
jsonArray.put(1);
jsonArray.put(2);
Editor editor = prefs.edit();
editor.putString("key", jsonArray.toString());
System.out.println(jsonArray.toString());
editor.commit();

Читать,

try {
    JSONArray jsonArray2 = new JSONArray(prefs.getString("key", "[]"));
    for (int i = 0; i < jsonArray2.length(); i++) {
         Log.d("your JSON Array", jsonArray2.getInt(i)+"");
    }
} catch (Exception e) {
    e.printStackTrace();
}
Рохит
источник
31

Общие предпочтения введены getStringSetи putStringSetметоды в API Level 11, но это не совместимо со старыми версиями Android (которые до сих пор популярны), а также ограничиваются наборами строк.

Android не предоставляет лучших методов, и цикл по картам и массивам для их сохранения и загрузки не очень прост и понятен, особенно для массивов. Но лучшая реализация не так уж и сложна:

package com.example.utils;

import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;

import android.content.Context;
import android.content.SharedPreferences;

public class JSONSharedPreferences {
    private static final String PREFIX = "json";

    public static void saveJSONObject(Context c, String prefName, String key, JSONObject object) {
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(JSONSharedPreferences.PREFIX+key, object.toString());
        editor.commit();
    }

    public static void saveJSONArray(Context c, String prefName, String key, JSONArray array) {
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(JSONSharedPreferences.PREFIX+key, array.toString());
        editor.commit();
    }

    public static JSONObject loadJSONObject(Context c, String prefName, String key) throws JSONException {
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        return new JSONObject(settings.getString(JSONSharedPreferences.PREFIX+key, "{}"));
    }

    public static JSONArray loadJSONArray(Context c, String prefName, String key) throws JSONException {
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        return new JSONArray(settings.getString(JSONSharedPreferences.PREFIX+key, "[]"));
    }

    public static void remove(Context c, String prefName, String key) {
        SharedPreferences settings = c.getSharedPreferences(prefName, 0);
        if (settings.contains(JSONSharedPreferences.PREFIX+key)) {
            SharedPreferences.Editor editor = settings.edit();
            editor.remove(JSONSharedPreferences.PREFIX+key);
            editor.commit();
        }
    }
}

Теперь вы можете сохранить любую коллекцию в общих настройках с помощью этих пяти методов. Работать с JSONObjectи JSONArrayочень просто. Вы можете использовать JSONArray (Collection copyFrom)открытый конструктор , чтобы сделать JSONArrayиз любой коллекции и использования Java JSONArray«s getметодов доступа к элементам.

Для общих предпочтений нет ограничений по размеру (помимо ограничений хранилища устройства), поэтому эти методы могут работать в большинстве обычных случаев, когда вам нужно быстрое и легкое хранилище для некоторой коллекции в вашем приложении. Но здесь происходит синтаксический анализ JSON, а предпочтения в Android хранятся в виде XML-файлов внутри, поэтому я рекомендую использовать другие механизмы постоянного хранения данных, когда вы имеете дело с мегабайтами данных.

Мостафа
источник
7
Если вы собираетесь использовать JSON, возможно, посмотрите gson: code.google.com/p/google-gson - он преобразует объекты java в JSON и обратно.
FeatureCreep
Это было бы интересное сочетание.
Мостафа
17

Простой режим для хранения сложных объектов с использованием библиотеки Gson google [1]

public static void setComplexObject(Context ctx, ComplexObject obj){
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
    SharedPreferences.Editor editor = preferences.edit();
    editor.putString("COMPLEX_OBJECT",new Gson().toJson(obj)); 
    editor.commit();
}

public static ComplexObject getComplexObject (Context ctx){
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
    String sobj = preferences.getString("COMPLEX_OBJECT", "");
    if(sobj.equals(""))return null;
    else return new Gson().fromJson(sobj, ComplexObject.class);
}

[1] http://code.google.com/p/google-gson/

Гпсатурн
источник
Лучший! Отметьте это как ОТВЕТ!
Renan Franca
3

Я загрузил массив размеров талии (уже созданный в моем array.xml) в свой файл preferences.xml с приведенным ниже кодом. @ array / pant_inch_size - это идентификатор всего массива.

 <ListPreference 
 android:title="choosepantsize"
 android:summary="Choose Pant Size"
 android:key="pantSizePref" 
 android:defaultValue="34" 
 android:entries="@array/pant_inch_size"
 android:entryValues="@array/pant_inch_size" /> 

Это заполнило меню вариантами из массива. Я установил размер по умолчанию 34, поэтому, когда всплывает меню, они видят, что размер 34 предварительно выбран.

Кит
источник
Привет, Кейт, спасибо за ответ. Мне нужно сохранить заказ, и я не работаю с пользовательским интерфейсом предпочтений, поэтому я не хочу, чтобы ваш код соответствовал тому, что мне нужно выполнить. В любом случае спасибо
zsniperx 05
ах !! Я неверно истолковал ваш вопрос, извините за это. Для любых других читателей мой XML-код просто берет элементы из моего файла array.xml и загружает их в меню предпочтений, при этом в данном случае в качестве предпочтения по умолчанию предварительно выбрано значение «34». Затем я использую java, чтобы найти идентификатор для этого конкретного предпочтения, которым является «pantSizePref» («ключ»).
Кейт
2

Самый простой способ - преобразовать его в строку JSON, как показано ниже:

Gson gson = new Gson();
String json = gson.toJson(myObj);

Затем сохраните строку в общих настройках. Как только вам это понадобится, просто получите строку из общих настроек и конвертируйте обратно в JSONArray или JSONObject (в соответствии с вашими требованиями).

Гаурав Дарджи
источник
2

Для записи:

 private <T> void storeData(String key, T data) {
    ByteArrayOutputStream serializedData = new ByteArrayOutputStream();

    try {
        ObjectOutputStream serializer = new ObjectOutputStream(serializedData);
        serializer.writeObject(data);
    } catch (IOException e) {
        e.printStackTrace();
    }

    SharedPreferences sharedPreferences = getSharedPreferences(TAG, 0);
    SharedPreferences.Editor edit = sharedPreferences.edit();

    edit.putString(key, Base64.encodeToString(serializedData.toByteArray(), Base64.DEFAULT));
    edit.commit();
}

Для чтения:

private <T> T getStoredData(String key) {
    SharedPreferences sharedPreferences = getSharedPreferences(TAG, 0);
    String serializedData = sharedPreferences.getString(key, null);
    T storedData = null;
    try {
        ByteArrayInputStream input = new ByteArrayInputStream(Base64.decode(serializedData, Base64.DEFAULT));
        ObjectInputStream inputStream = new ObjectInputStream(input);
        storedData = (T)inputStream.readObject();
    } catch (IOException|ClassNotFoundException|java.lang.IllegalArgumentException e) {
        e.printStackTrace();
    }

    return storedData;
}
Бенав
источник
Это кажется разумным предложением. Все общие коллекции реализуют Serializable, а ваши базовые String, Number и Date - Serializable. Единственным недостатком будет производительность.
androidguy
1

Это код общих настроек, который я успешно использую, перейдите по этой ссылке :

  public class MainActivity extends Activity {

private static final int RESULT_SETTINGS = 1;
Button button;
public String a="dd";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

 button = (Button) findViewById(R.id.btnoptions);


setContentView(R.layout.activity_main);

  // showUserSettings();
  }

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.settings, menu);
return true;
 }

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {

case R.id.menu_settings:
 Intent i = new Intent(this, UserSettingActivity.class);
 startActivityForResult(i, RESULT_SETTINGS);
 break;

 }

return true;
}

@Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data)     {
  super.onActivityResult(requestCode, resultCode, data);

 switch (requestCode) {
 case RESULT_SETTINGS:
 showUserSettings();
 break;

 } 

  }

  private void showUserSettings() {
 SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(this);

 StringBuilder builder = new StringBuilder();

 builder.append("\n Pet: "
  + sharedPrefs.getString("prefpetname", "NULL"));

 builder.append("\n Address:"
 + sharedPrefs.getString("prefaddress","NULL" ));

 builder.append("\n Your name: "
 + sharedPrefs.getString("prefname", "NULL"));

 TextView settingsTextView = (TextView) findViewById(R.id.textUserSettings);


  settingsTextView.setText(builder.toString());


    }

   }

С КОДИРОВКОЙ!

Dondondon
источник
0

Вы можете использовать putStringSet

Это позволит вам сохранить HashSet в ваших предпочтениях, вот так:

Сохранить

Set<String> values;

SharedPreferences sharedPref = 
    mContext.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);

Editor editor = sharedPref.edit();

editor.putStringSet("YOUR_KEY", values);
editor.apply();

Получить

SharedPreferences sharedPref = 
    mContext.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);

Editor editor = sharedPref.edit();

Set<String> newList = editor.getStringSet("YOUR_KEY", null);

PutStringSet позволяет использовать только Set, и это неупорядоченный список.

Даниэль Бельтрами
источник
0

Когда я столкнулся с этим, я получил решение для сериализации, в котором вы можете сериализовать свою строку, но я также придумал хак.

Прочтите это, только если вы не читали о сериализации, иначе спуститесь и прочитайте мой хак

Чтобы упорядочить элементы массива, мы можем сериализовать массив в одну строку (создав новый класс ObjectSerializer (скопируйте код из - www.androiddevcourse.com/objectserializer.html, замените все, кроме имени пакета))

Ввод данных в общих предпочтениях: введите описание изображения здесь

остальная часть кода в строке 38 - введите описание изображения здесь

Поместите следующий аргумент как это, чтобы, если данные не были извлечены, он возвращал пустой массив (мы не можем поместить пустую строку, потому что контейнер / переменная является массивом, а не строкой)

Подойдя к моему хакеру: -

Объедините содержимое массива в одну строку, поместив некоторый символ между каждым элементом, а затем разделите его, используя этот символ при извлечении. Coz добавить и получить String легко с общими настройками. Если вас беспокоит разделение, просто найдите «разделение строки в java».

[Примечание: это отлично работает, если содержимое вашего массива является примитивным, например string, int, float и т. Д. Это будет работать для сложных массивов, которые имеют свою собственную структуру, предположим телефонную книгу, но слияние и разделение станут немного сложный. ]

PS: Я новичок в Android, поэтому не знаю, хороший ли это хак, поэтому дайте мне знать, если вы найдете лучшие хаки.

Ритвеак
источник