0

I created a puzzle-game in which tiles can be shuffled to recreate an image. The app is nearly finished except for the part where I save the data so the game can be continued when the app is restarted. I found some information about SharedPreferences, but I understand it's not possible to save a List with it. I have an Integer List with the indices of the puzzle-pieces, which needs to be saved. I tried converting the List to a string and retrieving that, but it went bad and messed up my whole program. I'm not skilled enough to fix it, so I am reaching out to you. My question therefore is, how do I save my List of integers?

Sorry in advance if the question has been asked before, I have been looking on the internet for over two hours and I really need some help. :)

Nifty
  • 13
  • 5
  • Use a csv String, save it, then use the comma to break apart your String into proper ints when you restore it. – zgc7009 Dec 10 '14 at 15:48
  • I tried this, but my program threw an error when it tried to access the newly created List. – Nifty Dec 10 '14 at 15:50

3 Answers3

1

The right way is to convert to a String, and then put it in SharedPreferences. You can convert the List to a String like this:

public static String listIntToString(List<Integer> list) {
    StringBuilder s = new StringBuilder();
    for (int i: list)
        s.append(i).append(" ");
    return s.toString();
}

Now to get back to a List<Integer>:

public static List<Integer> stringToListInt(String s) {
    List<Integer> result = new ArrayList<>();
    Scanner scan = new Scanner(s);
    while (scan.hasNextInt())
        result.add(scan.nextInt());
    scan.close();
    return result;
}

This is much cleaner than messing about with files or databases or XML for something so simple.


Actually if you want to get cute then you can just convert the List<Integer> to a String using its .toString() method, and then use this to get back to the List<Integer>:

public static List<Integer> defaultStringToListInt(String s) {
    List<Integer> result = new ArrayList<>();
    Scanner scan = new Scanner(s);
    scan.useDelimiter(Pattern.compile("[, \\[\\]]+"));
    while (scan.hasNextInt())
        result.add(scan.nextInt());
    scan.close();
    return result;
}

That way, you only have to define one helper method. This works because the .toString() method on a List<Integer> comes out as something like

[1, 22, -3, 4, 5]

and the code above scans through looking for integers, using square brackets, commas and spaces as delimiters.

chiastic-security
  • 20,430
  • 4
  • 39
  • 67
  • I tried this, but it throws a NullPointerException "attempt to get length of null array", so I am doing something wrong, but what? – Nifty Dec 10 '14 at 16:18
  • 1
    @Nifty on which line? The code I gave you doesn't use any arrays... – chiastic-security Dec 10 '14 at 16:33
  • You're right, it's something I did wrong. I'm fixing it now and hope it works, thanks for the answer though! I think this is what I was looking for :) – Nifty Dec 10 '14 at 17:22
0

You could either use a database to store information that your app will retrieve when it restarts or (probably the easier method) is to save your list of integers to a file and read from it when your app restarts.

RobPio
  • 137
  • 8
0

I would suggest creating an XML, and then reading it to gather your data each time your app starts. You could do something like the following to write your XML;

// Create your document and it's root element.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
Element root = doc.createElement("root");
doc.appendChild(root);
// Loop through your list and create an xml element for each list element.
for(Integer i : yourList){
     Element listItem = doc.createElement("integer");       
     listItem.setAttribute("value", i.toString());
     root.appendChild(listItem);
}
// write the the Document to where-ever you want.
FileOutputStream fos = yourContext.openFileOutput("data_store.xml", Context.MODE_PRIVATE);
TransformerFactory factory = new TransformerFactory();
Transformer transformer = factory.newTransformer();
DOMSource source = new DOMSource(root);
StreamResult result = new StreamResult(fos);
transformer(source, result);

And to read your XML simply;

FileInputStream fis = yourContext.openFileInput("data_store.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fis);
// Get & loop through a list of all integer elements
NodeList nodes = doc.getElementsByTagName("integer");
for(Node n : nodes){
    if(n.getNodeType() == Node.ELEMENT_NODE){
        Element e = (Element) n;
        yourList.add(Integer.parseInt(e.getAttribute("value")));
    }        
}

Although the above is a little overkill, you may find yourself wanting to store other related details, in which case this solution is much more extensible. I hope this helps.

Further reading;

Rudi Kershaw
  • 12,332
  • 7
  • 52
  • 77