3

For my app, I need to save a simple SparseBooleanArray to memory and read it later. Is there any way to save it using SharedPreferences?

I considered using an SQLite database but it seemed overkill for something as simple as this. Some other answers I found on StackOverflow suggested using GSON for saving it as a String but I need to keep this app very light and fast in file size. Is there any way of achieving this without relying on a third party library and while maintaining good performance?

Pkmmte
  • 2,822
  • 1
  • 31
  • 41

4 Answers4

5

You can use the power of JSON to save in the shared preferences for any type of object

For example SparseIntArray Save items like Json string

public static void saveArrayPref(Context context, String prefKey, SparseIntArray intDict) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = prefs.edit();
    JSONArray json = new JSONArray();
    StringBuffer data = new StringBuffer().append("[");
    for(int i = 0; i < intDict.size(); i++) {
        data.append("{")
                .append("\"key\": ")
                .append(intDict.keyAt(i)).append(",")
                .append("\"order\": ")
                .append(intDict.valueAt(i))
                .append("},");
        json.put(data);
    }
    data.append("]");
    editor.putString(prefKey, intDict.size() == 0 ? null : data.toString());
    editor.commit();
}

and read json string

public static SparseIntArray getArrayPref(Context context, String prefKey) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    String json = prefs.getString(prefKey, null);
    SparseIntArray intDict = new SparseIntArray();
    if (json != null) {
        try {
            JSONArray jsonArray = new JSONArray(json);
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject item = jsonArray.getJSONObject(i);
                intDict.put(item.getInt("key"), item.getInt("order"));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    return intDict;
}

and use like this:

    SparseIntArray myKeyList = new SparseIntArray(); 
    ...
    //write list
    saveArrayPref(getApplicationContext(),"MyList", myKeyList);
    ...
    //read list
    myKeyList = getArrayPref(getApplicationContext(), "MyList");
missionMan
  • 873
  • 8
  • 21
3

Write the values separately, and keep a list of the names of the values you write:

    SparseBooleanArray array = //your array;
    SharedPreferences prefs = //your preferences

    //write
    SharedPreferences.Editor edit = prefs.edit();
    Set<String> keys = new HashSet<String>(array.size());
    for(int i = 0, z = array.size(); i < z; ++i) {
        int key = array.keyAt(i);
        keys.add(String.valueOf(key));
        edit.putBoolean("key_" + key, array.valueAt(i));
    }
    edit.putStringSet("keys", keys);
    edit.commit();

    //read
    Set<String> set = prefs.getStringSet("keys", null);
    if(set != null && !set.isEmpty()) {
        for (String key : set) {
            int k = Integer.parseInt(key);
            array.put(k, prefs.getBoolean("key_"+key, false));
        }
    }

String sets are supported since API 11. You could instead build a single csv string and split that rather than storing the set.

FunkTheMonk
  • 10,908
  • 1
  • 31
  • 37
1

You can serialize the object to a byte array and then probably base64 the byte array before saving to SharedPreferences. Object serialization is really easy, you don't need a third party library for that.

public static byte[] serialize(Object obj) {
    ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
    ObjectOutputStream objectOS = new ObjectOutputStream(byteArrayOS);
    objectOS.writeObject(obj);
    objectOS.flush();
    return byteArrayOS.toByteArray();
}

public static Object deserialize(byte[] data) {
    ByteArrayInputStream byteArrayIS = new ByteArrayInputStream(data);
    ObjectInputStream objectIS = new ObjectInputStream(byteArrayIS);
    return objectIS.readObject();
}

The code above doesn't have try catch block for simplicity. You can add it on your own.

Krypton
  • 3,337
  • 5
  • 32
  • 52
  • How good is this regarding performance? Also, I noticed that you're using a byte array for this. How should I save that byte array into the SharedPreferences if there is no method that allows that data type? – Pkmmte Jul 31 '14 at 04:26
  • Any form of serialization is slow. However unless your object reaches megabytes or bigger, the delay is really very unnoticeable. As I understood, you need to save only one array. I guess it will be OK. – Krypton Jul 31 '14 at 04:33
  • You need to base64 the byte array to turn it into a string before saving it. And then you need to de-base64 when reading it to get the byte array before deserializing. – Krypton Jul 31 '14 at 04:34
0

I have been doing this as the following by using Gson

To save sparseboolean array in SharedPreference:

public void SaveSparseBoolean() {
    SparseBooleanArray booleanArray = new SparseBooleanArray();
    SharedPreferences sP;
    sP=context.getSharedPreferences("MY_APPS_PREF",Context.MODE_PRIVATE)
    SharedPreferences.Editor editor=sP.edit();
    Gson gson=new Gson();
    editor.putString("Sparse_Array",gson.toJson(booleanArray));
    editor.commit();
}

To get the SparsebooleanArray from SharedPreferences

public SparseBooleanArray getSparseArray() {
    SparseBooleanArray booleanArray;
    SharedPreferences sP;
    sP = context.getSharedPreferences("MY_APPS_PREF", Context.MODE_PRIVATE);
    Gson gson=new Gson();
    booleanArray=gson.fromJson(sP.getString("Sparse_Array",""),SparseBooleanArray.class);
    return booleanArray;

}
Pallob
  • 31
  • 5