Android: Sort data retrieved from SharedPreferences - android

I am trying to store data in Android. I am using the SharedPreferences. And I am retrieving these data by using:
SharedPreferences myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
Map<String, ?> keys = myPrefs.getAll();
for (Map.Entry<String, ?> entry : keys.entrySet()) {
Log.i("map values", entry.getKey());
//some code
}
EDIT:
But data retrieved are not in the same order as they were inserted. How to get the same order?

Copy the resulting Map into an implementation of SortedMap, e.g. TreeMap.
Like this (sort by key):
SharedPreferences myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
TreeMap<String, ?> keys = new TreeMap<String, Object>(myPrefs.getAll());
for (Map.Entry<String, ?> entry : keys.entrySet()) {
Log.i("map values", entry.getKey());
//some code
}
To sort by value & not lose any key-value pairs (since a Map will readily allow duplicate values mapping to different keys) you'd need to first convert it into
a List and sort that.
List<Pair<Object, String>> sortedByValue = new LinkedList<Pair<Object,String>>();
for (Map.Entry<String, ?> entry : keys.entrySet()) {
Pair<Object, String> e = new Pair<Object, String>(entry.getValue(), entry.getKey());
sortedByValue.add(e);
}
// Pair doesn't have a comparator, so you're going to need to write one.
Collections.sort(sortedByValue, new Comparator<Pair<Object, String>>() {
public int compare(Pair<Object, String> lhs, Pair<Object, String> rhs) {
// This is a naive and shitty comparator, but it works for
// arbitrary objects. Sort of. Tweak depending on the order you need.
String sls = String.valueOf(lhs.first);
String srs = String.valueOf(rhs.first);
int res = sls.compareTo(srs);
// Sort on value first, key second
return res == 0 ? lhs.second.compareTo(rhs.second) : res;
}
});
for (Pair<Object, String> pair : sortedByValue) {
Log.i("map values", pair.first + "/" + pair.second);
}

Add a property with the order, like so...
First save the settings...
public static void saveSettings(final Editor editor, final String [] order) {
final String csl = toString(order);//comma separated
editor.putString("insert_order", csl);
for (int i = 0; i < values.length; i++) {
editor.putString(values[i], your_value[i]);
}
}
Now load them:
public static List<String> loadSetting(final SharedPreferences preferences) {
final List<String> inOrder = new ArrayList<>();
final String[] ordering = preferences.getString("insert_order", "").split(",");
for (final String item : ordering) {
final String value = (String) preferences.getString(item, "");
inOrder.add(value);
}
return inOrder;
}

Related

Set json object's key in android

I have this json file:
[ { “dir radix”: [ {”dir1”:”dir”}, {”dir3”:”dir”},] },
{ “dir1”: [ {”dir11”:”dir”}, {”dir12”:”dir”}]},
{ “dir3”: []}
]
How can I set the key "dir radix" or the others?
I use this code to search the right key that I want to rename:
try {
parse = new JSONArray(temp);
//temp is the string returned by the reading of the file json
JSONObject obj = new JSONObject();
for (i = 0; i < parse.length() && flag == 0; i++) {
obj = parse.getJSONObject(i);
Iterator iterator = obj.keys();
while (iterator.hasNext() && flag == 0) {
String key = (String) iterator.next();
//elem is the selected item that I want to rename
if (elem.equals(key)) {
flag = 1;
//set json's key
}
}
}
writefile(parse.toString(),f);
} catch (Exception e) {
e.printStackTrace();
}
There is no possibility to replace json object key, so maybe you can remove object and add new object with new key. Try that code
String newKey = "NEW_KEY";
String elem = "OLD_KEY";
String temp = "SRC_JSON";
int flag = 0;
JSONArray parse = new JSONArray(temp);
//temp is the string returned by the reading of the file json
JSONObject obj = null;
for (int i = 0; i < parse.length() && flag == 0; i++) {
obj = parse.getJSONObject(i);
Iterator iterator = obj.keys();
while (iterator.hasNext() && flag == 0) {
String key = (String) iterator.next();
//elem is the selected item that I want to rename
if (elem.equals(key)) {
flag = 1;
//set json's key
JSONArray array = obj.getJSONArray(key);
obj.remove(key);
obj.put(newKey, array);
}
}
}
JSONObject in java represents a mapping, so you can't easily change a key. You can, however, remove a value and re-add that value with a different key. Here's a convenience method that can help:
public static void changeKey(JSONObject object, String oldKey, String newKey) throws JSONException {
if (!object.has(oldKey)) {
// key doesn't exist, quit early
return;
}
Object oldData = object.get(oldKey);
object.remove(oldKey);
object.put(newKey, oldData);
}
And in your scenario, you no longer have to loop through the keys. You can simply call like this:
changeKey(obj, key, "new_key");

How to get Hashmap Data

I had seen many examples regarding Hashmap Data but I am not getting the data as required.
Here is my code:
HashMap<String,ArrayList<String>> citylist = new HashMap<String, ArrayList<String>>();
ArrayList<String> Gujarat = new ArrayList<String>();
Gujarat.add("Surat");
Gujarat.add("Baroda");
Gujarat.add("Ahmedabad");
ArrayList<String> Rajasthan = new ArrayList<String>();
Rajasthan.add("Udaipur");
Rajasthan.add("Jaipur");
ArrayList<String> UP= new ArrayList<String>();
UP.add("Lucknow");
UP.add("Agra");
citylist.put("Gujarat", Gujarat);
citylist.put("UP", UP);
citylist.put("Rajasthan", Rajasthan);
It is in recyclerview how to get this type of data in BindViewHolder?
Toast is coming like:
{Rajasthan=[Udaipur, Jaipur], UP=[Lucknow, Agra], Gujarat=[Surat, Baroda, Ahmedabad]}
I had used this method to get but error is coming:
public void onBindViewHolder(MyViewHolder holder, int position) {
ArrayList<String> lst = citylist.get("" + position);
for (Integer i = 0; i < lst.size(); i++) {
holder.tv.setText(citylist.toString());
Log.e("Hashmap....", ""+holder.tv );
}
the output should be like Gujarat is state and surat baroda and ahmedabad are cities?
First create one ArrayList with all state :
ArrayList<String> stateList = new ArrayList<String>();
stateList.add("Gujarat");
stateList.add("UP");
stateList.add("Rajasthan");
Second create one HashMap with each state name as Key and each state city as Value:
HashMap<String,ArrayList<String>> stateCityMap = new HashMap<String,ArrayList<String>>()
ArrayList<String> gujaratCityList = new ArrayList<String>();
gujaratCityList.add("Ahmedabad");
gujaratCityList.add("Surat");
gujaratCityList.add("Baroda");
.......................
ArrayList<String> upCityList = new ArrayList<String>();
upCityList.add("Lucknow");
upCityList.add("Agra");
..........................
ArrayList<String> rajasthanCityList = new ArrayList<String>();
rajasthanCityList.add("Udaipur");
rajasthanCityList.add("Jaipur");
...........................
stateCityMap.put("Gujarat",gujaratCityList);
stateCityMap.put("UP",upCityList);
stateCityMap.put("Rajasthan",rajasthanCityList);
Now get all city name based on state in Adapter :
public void onBindViewHolder(MyViewHolder holder, int position) {
Log.e("State : ",stateList.get(position));
ArrayList<String> cityList= (ArrayList<String>)stateCityMap.get(stateList.get(position));
for(String cityName : cityList){
Log.e("City : ",cityName);
}
}
you can get like below.
Iterator iterator = map.keySet().iterator();
while(iterator.hasNext()) {
String key=(String)iterator.next();
String value=(String)map.get(key);
Toast.makeText(ctx, "Key: "+key+" Value: "+value, Toast.LENGTH_LONG).show();
}
HashMaps do not preserve ordering:
This class makes no guarantees as to the order of the map; in
particular, it does not guarantee that the order will remain constant
over time.
Take a look at LinkedHashMap, which guarantees a predictable iteration order.
You might wanna try something like this.
for (Map.Entry<String, ArrayList<String>> entry : citylist.entrySet())
{
String key = entry.getKey(); // Your State
String value = entry.getValue(); // Your List of Cities.
// Split data and insert in Views
}
However I recommend (for easy to use case) keep a List of all the states and get Value from HashMap using keys from this List of states.
Please check it :
ArrayList<HashMap<String, String>> arrayList = new ArrayList<HashMap<String,String>>();
HashMap<String, String> h1 = new HashMap<String, String>();
h1.put("h1_key_1", "h1_value_1");
h1.put("h1_key_2", "h1_value_2");
arrayList.add(h1);
for (HashMap<String, String> hashMap : arrayList) {
System.out.println(hashMap.keySet());
for (String key : hashMap.keySet()) {
System.out.println(hashMap.get(key));
}
}
Try This:
public static void printMap(Map mp) {
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}

Save SparseBooleanArray to SharedPreferences

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?
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");
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.
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.
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;
}

How can I store an integer array in SharedPreferences?

I want to save/recall an integer array using SharedPreferences. Is this possible?
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());
}
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;
}
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;
}
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.
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.
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)
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())
You can only save primitive values in sharedPreference. Use Sqlite instead.

android array from shared preferences

I'm trying to iterate over a collection of shared preferences, and generate an ArrayList of HashMaps, but having an issue.
SharedPreferences settings = getSharedPreferences(pref, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("key1", "value1");
editor.putString("key2", "value2");
and then I was thinking something along the lines of:
final ArrayList<HashMap<String,String>> LIST = new ArrayList<HashMap<String,String>>();
SharedPreferences settings = getSharedPreferences(pref, 0);
Map<String, ?> items = settings.getAll();
for(String s : items.keySet()){
HashMap<String,String> temp = new HashMap<String,String>();
temp.put("key", s);
temp.put("value", items.get(s));
LIST.add(temp);
}
This gives the following error:
The method put(String, String) in the type HashMap<String,String> is not applicable for the arguments (String, capture#5-of ?)
Is there a better way to do this?
Hache had the correct idea. An Object is not a String, so .toString() was necessary.
final ArrayList<HashMap<String,String>> LIST = new ArrayList<HashMap<String,String>>();
SharedPreferences settings = getSharedPreferences(pref, 0);
Map<String, ?> items = settings.getAll();
for(String s : items.keySet()){
HashMap<String,String> temp = new HashMap<String,String>();
temp.put("key", s);
temp.put("value", items.get(s).toString());
LIST.add(temp);
}
Change
HashMap<String,String> temp = new HashMap<String,String>();
final ArrayList<HashMap<String,String>> LIST = new ArrayList<HashMap<String,String>>();
to
HashMap<String,?> temp = new HashMap<String,?>();
final ArrayList<HashMap<String,?>> LIST = new ArrayList<HashMap<String,?>>();
and it should work. You're not putting an String but an object this causes the error

Categories

Resources