Не удается контролировать порядок набора строк в общих настройках

Это мой первый вопрос stackru. Я много гуглил по этому вопросу. На Hashsets, Treesets, LinkedHashSets, Collections, Stacks (класс Stack устарел?)... Я понимаю, что мог бы просто использовать SQLite, но пока пытаюсь избежать этого.

Я работаю над приложением в Android Studio. Приложение имеет дело с людьми, перечисляя их и связываясь с ними по-разному. Пользователи приложения могут поддерживать и контролировать три типа списков: недавно подключенные, заблокированные и избранные. Эти списки сохраняются как наборы строк в общих настройках, поэтому они сохраняются после закрытия и повторного открытия приложения. Отдельные строки действуют как первичные ключи, когда списки заполняются с использованием онлайн-базы данных. Меня больше всего беспокоит список "недавно соприкосновений", потому что порядок этого списка имеет значение.

Проблема в том, что, насколько я понимаю, когда я объявляю набор строк, он выглядит следующим образом:

Set<String> faveArray = new LinkedHashSet<String>;

Как я понимаю, я могу использовать только HashSet, LinkedHashSet или TreeSet с правой стороны.

Поскольку я использовал LinkedHashset, я ожидал, что при повторном открытии приложения и извлечении данных из разделяемых настроек строки будут извлечены, начиная с самого последнего добавленного (LIFO / стек), и, следовательно, при заполнении списка просмотра, они будут показываться с человеком, с которым недавно связывались, в верхней части списка и так далее... или, по крайней мере, я ожидал иметь какой-то предсказуемый порядок / поведение, с которым я мог бы работать.

Итак....... Я прикрепил свой код для своего класса ввода / вывода с общими предпочтениями.

Из моего основного приложения я делаю что-то вроде:

static SharedPrefUTIL sharedPrefUTIL;

sharedPrefUTIL = new SharedPrefUTIL(this);

sharedPrefUTIL.addRecent("derp");
sharedPrefUTIL.addRecent("nerp");
sharedPrefUTIL.addRecent("gerp");
sharedPrefUTIL.addRecent("herp");

На данный момент код

Log.i(TAG, set + " committed to " + key);

в методе commit() класса SharedPrefUTIL Журналы:

"[derp, nerp, gerp, herp], преданный недавнему массиву"

Но после закрытия и повторного открытия приложения, если мы выполним:

sharedPrefUTIL.toastContents("R");

Результат, казалось бы, случайный порядок. <<<< это моя проблема.

Любая помощь с благодарностью.

package com.secretsoft.booberbunz;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;

/**
* Created by Programming on 2/22/2016.
*/
public class SharedPrefUTIL {

protected static final String TAG = "CXX SharedPrefUTIL";

Context context;

SharedPreferences sharedPreferences;

Set<String> faveArray;
Set<String> blockArray;
Set<String> recentArray;

public static final Set<String> DEFAULT = new HashSet<String>(Arrays.asList("empty"));


public SharedPrefUTIL(Context context){

    this.context = context;

    // load shared prefs into static arrays (new objects to prevent problems)

    sharedPreferences = context.getSharedPreferences("prefs", Context.MODE_PRIVATE);

    recentArray = new LinkedHashSet<String>(sharedPreferences.getStringSet("recentArray",DEFAULT));
    blockArray = new LinkedHashSet<String>(sharedPreferences.getStringSet("blockArray",DEFAULT));
    faveArray = new LinkedHashSet<String>(sharedPreferences.getStringSet("faveArray",DEFAULT));

    Log.i(TAG, "SharedPrefUTIL instance created");


    if (recentArray.contains("empty")) {
        recentArray.clear();

        Log.i(TAG, "recentArray contains the string -empty- and was cleared");
    }

    if (blockArray.contains("empty")) {
        blockArray.clear();

        Log.i(TAG, "blockArray contains the string -empty- and was cleared");
    }

    if (faveArray.contains("empty")) {
        faveArray.clear();

        Log.i(TAG, "faveArray contains the string -empty- and was cleared");
    }

}

public void toastLength(String type){

    if (type == "R"){

        String temp = type + " array is this long: " + recentArray.size();

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, temp);


    }

    else if (type == "B"){

        String temp = type + " array is this long: " + blockArray.size();

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, temp);

    }

    else if (type == "F"){

        String temp = type + " array is this long: " + faveArray.size();

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, temp);

    }

    else {
        Log.i(TAG, "invalid type param given to toastLength()");
    }

}


public void toastContents(String type){

    if (type == "R"){

        for (String temp : recentArray) {

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, "recentArray contains: " + temp);

    }

    }

    else if (type == "B"){

        for (String temp : blockArray) {

            Toast.makeText(context, temp,
                    Toast.LENGTH_LONG).show();

            Log.i(TAG, "blockArray contains: " + temp);

        }

    }

    else if (type == "F"){

        for (String temp : faveArray) {

            Toast.makeText(context, temp,
                    Toast.LENGTH_LONG).show();

            Log.i(TAG, "faveArray contains: " + temp);

        }
    }

    else {
        Log.i(TAG, "invalid type param given to toastContents()");
    }



}

public void clearList(String type){
    if (type == "R"){
        recentArray.clear();

        commit("recentArray", recentArray);

        Toast.makeText(context,"recent list has been cleared.", Toast.LENGTH_LONG);
    }

    else if (type == "B"){

        blockArray.clear();

        commit("blockArray", blockArray);

        Toast.makeText(context,"blacklist has been cleared.", Toast.LENGTH_LONG);

    }

    else if (type == "F"){

        faveArray.clear();

        commit("faveArray", faveArray);

        Toast.makeText(context,"favorites have been cleared.", Toast.LENGTH_LONG);

    }

    else {
        Log.i(TAG, "invalid type param given to clearList()");
    }

}

public void addRecent(String newRecent){
    recentArray.add(newRecent);
    commit("recentArray", recentArray);
    Log.i(TAG, newRecent + " added to recentArray");
}

public void addBlocked(String newBlocked, String  nick){
    blockArray.add(newBlocked);
    commit("blockArray", blockArray);
    Toast.makeText(context, nick + " has been blacklisted!", Toast.LENGTH_SHORT);
}

public void remBlocked(String remBlocked, String nick){
    blockArray.remove(remBlocked);
    commit("blockArray", blockArray);
    Toast.makeText(context, nick + " has been unblocked.", Toast.LENGTH_SHORT);
}

public void addFave(String newFave, String nick){
    faveArray.add(newFave);
    commit("faveArray", faveArray);
    Toast.makeText(context, nick + " added to favorites!", Toast.LENGTH_SHORT);

}

public void remFave(String remFave, String nick){
    faveArray.remove(remFave);
    commit("faveArray", faveArray);
    Toast.makeText(context, nick + " removed from favorites.", Toast.LENGTH_SHORT);
}

public void commit(String key, Set<String> set){
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putStringSet(key,set);
    editor.commit();
    Log.i(TAG, set + " committed to " + key);
}




}

2 ответа

Решение

К сожалению, вы просто нашли ограничение SharedPreferences,

Пока вы используете упорядоченный хеш, он не загружает их упорядоченными при вызове getStringSet,

Самый простой способ сделать это - преобразовать массив в текст, упорядочить, а затем сохранить его в SharedPreferences. Android поставляется с объектом JSONArray это может сделать это.

http://developer.android.com/reference/org/json/JSONArray.html

Вот некоторый псевдокод, который будет делать то, что вы хотите:

public void saveOrderedCollection(Collection collection, String key){
    JSONArray jsonArray = new JSONArray(collection);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putString(key, jsonArray.toString());
    editor.commit();
}

public Collection loadOrderedCollection(String key){
    ArrayList arrayList = new ArrayList;
    SharedPreferences.Editor editor = sharedPreferences.edit();
    JSONArray jsonArray = new JSONArray(editor.getString(key, "[]"));
    for (int i = 0; i < jsonArray.length(); i++) {
        arrayList.put(jsonArray.get(i));
    }
    return arrayList;
}

Вот некоторые другие сообщения, которые я использовал, чтобы сделать это:

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

В общих настройках, как хранить массив строк в приложении Android

Используя kotlin, вы можете просто написать функции расширения для хранения списка строк, которые сохраняют порядок, как вы их добавили:

   fun SharedPreferences.Editor.putStringList(key: String, list: List<String>) {
        this.putString(key, list.joinToString(";"))
    }

   fun SharedPreferences.getStringList(key: String): List<String> {
        return this.getString(key, "")?.split(";") ?: listOf()
    }

Затем вы можете сохранить свои значения следующим образом:

sharedPrefs.edit().putStringList("SOME_KEY", listOf("A", "B", "C"))

И получайте их вот так:

val myList = sharedPrefs.getStringList("SOME_KEY")

Я реализовал предложенные изменения (используя строки JSON вместо наборов строк при сохранении в общие prefs) и вот новый код для моего общего класса pref на тот случай, если кто-то другой попытается сделать то же самое. Вероятно, излишнее количество ошибок в журналах устранения неполадок, но так я и поступаю, так как не знаю, как правильно отлаживать.

package [];

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast;

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

import java.util.LinkedHashSet;
import java.util.Set;


/**
 * Created by Programming on 2/22/2016.
 */
public class SharedPrefUTIL {

protected static final String TAG = "CXX SharedPrefUTIL";

Context context;

SharedPreferences sharedPreferences;

Set<String> recentArray;
Set<String> blockArray;
Set<String> faveArray;

JSONArray recentJArray;
JSONArray blockJArray;
JSONArray faveJArray;


public SharedPrefUTIL(Context context){

    this.context = context;

    // START load arrays from shared prefs

    sharedPreferences = context.getSharedPreferences("prefs", Context.MODE_PRIVATE);

    try {
        recentJArray = new JSONArray(sharedPreferences.getString("recentArray","[]"));
        blockJArray = new JSONArray(sharedPreferences.getString("blockArray","[]"));
        faveJArray = new JSONArray(sharedPreferences.getString("faveArray","[]"));
    } catch (JSONException e) {
        e.printStackTrace();
        Log.i(TAG, e.toString());
    }

    Log.i(TAG, "length of recentJArray is " + recentJArray.length());

    recentArray = new LinkedHashSet<String>();
    blockArray = new LinkedHashSet<String>();
    faveArray = new LinkedHashSet<String>();

    for (int i = 0; i < recentJArray.length(); i++) {

        try {
            recentArray.add(recentJArray.getString(i));
        } catch (JSONException e) {
            e.printStackTrace();
            Log.i(TAG, e.toString());
        }

    }

    for (int i = 0; i < blockJArray.length(); i++) {

        try {
            blockArray.add(blockJArray.getString(i));
        } catch (JSONException e) {
            e.printStackTrace();
            Log.i(TAG, e.toString());
        }

    }

    for (int i = 0; i < faveJArray.length(); i++) {

        try {
            faveArray.add(faveJArray.getString(i));
        } catch (JSONException e) {
            e.printStackTrace();
            Log.i(TAG, e.toString());
        }

    }

    // END load arrays from shared prefs

    Log.i(TAG, "SharedPrefUTIL instance created");

}

public void toastLength(String type){

    if (type == "R"){

        String temp = type + " array is this long: " + recentArray.size();

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, temp);


    }

    else if (type == "B"){

        String temp = type + " array is this long: " + blockArray.size();

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, temp);

    }

    else if (type == "F"){

        String temp = type + " array is this long: " + faveArray.size();

        Toast.makeText(context, temp,
                Toast.LENGTH_LONG).show();

        Log.i(TAG, temp);

    }

    else {
        Log.i(TAG, "invalid type param given to toastLength()");
    }

}


public void toastContents(String type){

    if (type == "R"){

        for (String temp : recentArray) {

            Toast.makeText(context, temp, Toast.LENGTH_LONG).show();

            Log.i(TAG, "recentArray contains: " + temp);

        }

    }

    else if (type == "B"){

        for (String temp : blockArray) {

            Toast.makeText(context, temp,
                    Toast.LENGTH_LONG).show();

            Log.i(TAG, "blockArray contains: " + temp);

        }

    }

    else if (type == "F"){

        for (String temp : faveArray) {

            Toast.makeText(context, temp,
                    Toast.LENGTH_LONG).show();

            Log.i(TAG, "faveArray contains: " + temp);

        }
    }

    else {
        Log.i(TAG, "invalid type param given to toastContents()");
    }



}

public void clearList(String type){
    if (type == "R"){
        recentArray.clear();

        commit("recentArray", recentArray);

        Toast.makeText(context,"recent list has been cleared.", Toast.LENGTH_LONG);
    }

    else if (type == "B"){

        blockArray.clear();

        commit("blockArray", blockArray);

        Toast.makeText(context,"blacklist has been cleared.", Toast.LENGTH_LONG);

    }

    else if (type == "F"){

        faveArray.clear();

        commit("faveArray", faveArray);

        Toast.makeText(context,"favorites have been cleared.", Toast.LENGTH_LONG);

    }

    else {
        Log.i(TAG, "invalid type param given to clearList()");
    }

}

public void addRecent(String newRecent){
    recentArray.add(newRecent);
    commit("recentArray", recentArray);
    Log.i(TAG, newRecent + " added to recentArray");
}

public void addBlocked(String newBlocked){
    blockArray.add(newBlocked);
    commit("blockArray", blockArray);
    Toast.makeText(context, newBlocked + " has been blacklisted!", Toast.LENGTH_SHORT);
}

public void remBlocked(String remBlocked){
    blockArray.remove(remBlocked);
    commit("blockArray", blockArray);
    Toast.makeText(context, remBlocked + " has been unblocked.", Toast.LENGTH_SHORT);
}

public void addFave(String newFave){
    faveArray.add(newFave);
    commit("faveArray", faveArray);
    Toast.makeText(context, newFave + " added to favorites!", Toast.LENGTH_SHORT);

}

public void remFave(String remFave){
    faveArray.remove(remFave);
    commit("faveArray", faveArray);
    Toast.makeText(context, remFave + " removed from favorites.", Toast.LENGTH_SHORT);
}

public void commit(String key, Set<String> set){

    // convert set into JSON

    JSONArray jsonArray = new JSONArray(set);

    Log.i(TAG, "During commit, jsonArray(set) is this long: " + jsonArray.length());

    //-------------------------------------------


    // commit changes
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putString(key,jsonArray.toString());
    editor.commit();
    Log.i(TAG, jsonArray.toString() + " committed to " + key);

}

}
Другие вопросы по тегам