Storing an arraylist for retrieval in Android - android

I'm currently working on an Android application that is going to be somewhat like a student planner. My backend is all java and I am currently stuck because i am storing the objects that i create from my backend to arraylist. Being java, these objects dissapear as soon as the programs terminate. Whats the easiest way that i can store my java objects for retrieval the next time i boot my application? Any help is much appreciated! Im developing on 2.3 and eclipse(juno).

One of the data storage options listed in the Android developer tutorial will be the easiest thing to do. Which is the best fit will depend on how much data you're storing and how you need to access it. As the page says, the SharedPreferences class is best for a handful of items; for larger data sets, you could use Java serialization or some other way to write them to a file on the phone's storage; and if your data are large and/or you need structured access to them, an SQLite database is your best bet.

You can use Shared Preferences to store your data. The SharedPreferences lets you persist key-value pairs of primitive data types in you application. You can't store an entire ArrayList with a single key, but you can iterate over the array and systematically generate a key for each value in the list. I usually do something like this:
public class SomeActivity extends Activity {
private ArrayList<Data> list; //We'll persist this array
/* snip */
//These strings can be anything - you just need something you can use to systematically generate distinct keys
public static final String LIST_KEY = "SomeActivity_List";
public static final String LIST_LENGTH_KEY = "SomeActivity_ListLength";
/**
* How this method works: It starts by getting a SharedPreferences object,
* which offers an API for persisting data. It then systematically generates
* Strings like "SomeActivity_List1", "SomeActivity_List2", "SomeActivity_List3",
* and so on to use as keys fot the 1st, 2nd, 3rd, etc. elements in the list. Then
* it Data.saveData(), a method defined below in the Data class, in order to give
* each Data object in the ArrayList an opportunity to persist its primitive
* members in the SharedPreferences.
*
* SomeActivity.restoreList() works similarly.
*/
public void saveList() {
SharedPreferences prefs = getPreferences(); //This method is part of the Activity class
SharedPreferences.Editor editor = prefs.getEditor();
//Save the length of the list so that when we restore it, we know how many
//Data objects to recreate.
editor.putInt(LIST_LENGTH_KEY, list.size());
editor.commit();
//This for loop is important - note how we concatenate i to each of the keys to give each element in list a distinct key
for(int i = 0; i < list.size(); i++)
{
String identifier = LIST_KEY + Integer.toString(i); //generate distinct keys
list.get(i).saveData(identifier, prefs);
}
}
public void restoreList() {
SharedPreferences prefs = getPreferences();
int length = prefs.getInt(LIST_LENGTH_KEY);
for(int i = 0; i < length; i++)
{
String identifier = LIST_KEY + Integer.toString(i); //re-generate distinct keys
Data data = new Data();
data.restoreData(identifier, prefs);
list.addLast(data);
}
}
public static class Data {
private int i;
private double j;
private String s;
public static final String I_KEY = "Data_I"
public static final String J_KEY = "Data_J" //strings can really be whatever, as long as they're distinct.
public static final String S_KEY = "Data_K"
/**
* How this method works: The SomeActivity.saveList() method generates a
* unique String ("identifier") for each of the Data objects it contains.
* This method uses that distinct string and makes some more distinct keys
* to store each of Data's primitive members.
*
* restoreData() works similarly when it rebuilds Data objects
*/
public saveData(String identifier, SharedPreferences prefs) {
SharedPreferences.Editor editor = prefs.getEditor();
editor.putInt(I_KEY + identifier, i);
editor.putDouble(J_KEY + identifier, j);
editor.putString(S_KEY + identifier, s);
editor.commit();
}
public restoreData(String identifier, SharedPreferences prefs) {
i = prefs.getInt(I_KEY + identifier);
j = prefs.getDouble(J_KEY + identifier);
s = prefs.getString(S_KEY + identifier);
}
}
}
This approach work recursively. If Data had an ArrayList as one of its fields, for example, it could systematically store all of the values in that list in SharedPreferences as well.
FYI: One of the implications of using SharedPreferences is that if the user uninstalls your app or clears the app data, the stored list will be deleted. Depending on the nature of your data, you may or may not want this behavior.

Related

How can I save user-created objects to storage in android?

In my app, I have flashcard objects that the user creates themselves. Users can create as many flashcards as they want, but when they exit the app and return they need to be able to see the flashcards that they previously created and be able to delete them. I have it set up so that they can create/delete, but if they exit the app they will all delete automatically. What is the best way to save the information for a flashcard? It has at least 3 strings currently, the title, the front and the back.
I looked at a few, but am not sure how I would include all three strings in the saving options that are on the android developer site.
For example shared preferences, looks like you can only save certain settings, but it allows the user to change those settings.
The internal/external storage, although very different throw up the same problem, how to have unlimited number of objects and especially how to save all three strings separately.
This is the internal storage is shown below.
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
I don't see how you can save multiple number of objects or 3 different strings.
Does anyone see a solution to my problem?
SharedPreferences seem like the simplest way for you to achieve it, and I think you've misunderstood their usage, or confused the name with a 'Preferences' screen, as you can use the SharedPreferences methods to save anything (well, any basic datatype) persistently.
For example, I use it to save my app's JSON data (which might be a decent way for you to go in terms of saving you users' flashcards in a JSONArray).
/**
* Retrieves data from sharedpreferences
* #param c the application context
* #param pref the preference to be retrieved
* #return the stored JSON-formatted String containing the data
*/
public static String getStoredJSONData(Context c, String pref) {
if (c != null) {
SharedPreferences sPrefs = c.getSharedPreferences("AppPreferences", Context.MODE_PRIVATE);
return sPrefs.getString(pref, null);
}
return null;
}
/**
* Stores the most recent data into sharedpreferences
* #param c the application context
* #param pref the preference to be stored
* #param policyData the data to be stored
*/
public static void setStoredJSONData(Context c, String pref, String policyData) {
if (c != null) {
SharedPreferences sPrefs = c.getSharedPreferences("AppPreferences", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sPrefs.edit();
editor.putString(pref, policyData);
editor.commit();
}
}
Where the string 'pref' is a tag used to refer to that specific piece of data, so for example: "taylor.matt.data1" would refer to a piece of data and could be used to retrieve or store it from SharedPreferences

How to save variables with SharedPreferences

I have my own Objects which I need to store for later use. The User saves this object, it is turned into a JSON String, then when the User is connected to a network, the JSON String is turned back into the object operations are performed on it.
My problem is that, at run time, how do I know how to store the object?
i.e
Gson gson= new Gson();
String pointOfInterest = gson.toJson(point);
SharedPreferences.Editor sharedprefEditor = application_shared_preferences.edit();
sharedprefEditor.putString(?KEY?,pointOfInterest);
What can I use for the value of KEY? If I use an index, it will get reset every time I open or close the app, and this will replace my Objects.
Edit
Sorry I didn't make this clear enough, the method that the above code is in can be run an arbitrary number of times and there could be several pointsOfInterest to store.
First of all, if you use an index, the Preference will stay forever:
For instance:
sharedprefEditor.putString("JSON569",pointOfInterest);
You can also save the index in an other preference; for instance separated by a column:
sharedprefEditor.putString("indexes","569;789;852");
You can, easily check if an instance exists:
myPreference.getString("JSON789","").contentEquals("");
Or get all your instances:
for (int anIndex:indexes)
    Log.i("TAG","Current value: "+myPreference.getString("JSON"+anIndex,""));
Please xplain a little bit more your question, I see no difficulties there/
You can name the key whatever you want, just make it consistent. One way to do it is make a constant in your class for it:
public class MyClass {
private static final String OBJECT_KEY = "myObjectKey";
...
Then when you save your object:
Gson gson= new Gson();
String pointOfInterest = gson.toJson(point);
SharedPreferences.Editor sharedprefEditor = application_shared_preferences.edit();
sharedprefEditor.putString(OBJECT_KEY,pointOfInterest);
When you load it, just use OBJECT_KEY to get a string out of the shared preferences:
String objectString = sharedPrefs.getString( OBJECT_KEY, "" );

Appropriate storage and display of my bookmarks/history activity?

I want a simple bookmarks and/or history for my app, and I'm wondering what the most appropriate storage would be? A text in a text file or preference, or perhaps a database? Which would be most flexible across updates, and efficient for space and lookup time?
For the display, I'm thinking this would be a good starting point, but would it be easy to add an icon to some items?
Edit:
I finally set up a Bookmark activity that should connect to a database:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bookmarkview);
Cursor cursor = managedQuery(getIntent().getData(), new String[] {Bookmark.TITLE, Bookmark.URL},
null, null, Bookmark.DEFAULT_SORT_ORDER);
setListAdapter(new SimpleCursorAdapter(this, R.layout.bookmarkitem, cursor,
new String[] { Bookmark.TITLE }, new int[] { android.R.id.text1 }));
findViewById(R.id.addBookmark).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ContentValues values = new ContentValues();
values.put("url", _url);
values.put("title", _title);
// When the update completes,
// the content provider will notify the cursor of the change, which will
// cause the UI to be updated.
getContentResolver().update(_myuri, values, null, null);
}
});
}
Bookmark.java:
package com.tunes.viewer.Bookmarks;
import android.net.Uri;
import android.provider.BaseColumns;
/*
* Database will have:
* pk - primary key
* title - the name of the bookmark.
* url - the url.
*/
public class Bookmark implements BaseColumns{
public static final String AUTHORITY = "com.tunes.viewer";
/**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/Bookmarks");
/**
* The MIME type of {#link #CONTENT_URI} providing a directory of notes.
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
/**
* The MIME type of a {#link #CONTENT_URI} sub-directory of a single note.
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";
/**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "title";
/**
* The title of the note
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
/**
* The url
* <P>Type: TEXT</P>
*/
public static final String URL = "url";
}
I seem to have fixed most of the problems I was having, but unfortunately it doesn't add to the database when I click the Add button (calling the onclick above). Furthermore, I added data to the database, but it doesn't show up in the view. What's wrong with the cursor/adapter here? Full source is here.
i would suggest, you go with database. It will be easy and efficient solution for your requirement.
A single table in sqlite will suffice to your requirements. as you will need to maintain a list of url you visited. this table will also serve your requirement of storing bookmark.
your table format could be something like this.
_____________________________________________________________________________________
Id(Auto-increment) | Title of page | Url of Page |name of icon(if needed) |isBookmark |
_____________________________________________________________________________________
This could be a good structure to achieve you requirement. set isBookmark to 0/1 to set specific link as bookmark or unbookmark it.
EDIT
I did not suggest you to use SharedPreferences and i wont (though it is straight forword and easy to implement) and reason lies in very definition of SharedPreferences which says:
"The SharedPreferences class provides a general framework that allows you to save and retrieve persistent key-value pairs of primitive data types. You can use SharedPreferences to save any primitive data: booleans, floats, ints, longs, and strings."
Now i can not imagine a single way to store ArrayList<String>(Urls) in one of these primitive datatypes.
There is one more work around.and it is Object Serialization. you can save your complete arraylist instance to a file and next time when you need this object, deseralize it similarly.. Here is the sample code for Serialization.
.
public void serializeMap(ArrayList<String> list) {
try {
FileOutputStream fStream = openFileOutput(namefile.bin, Context.MODE_PRIVATE) ;
ObjectOutputStream oStream = new ObjectOutputStream(fStream);
oStream.writeObject(list);
oStream.flush();
oStream.close();
Log.v("Serialization success", "Success");
} catch (Exception e) {
Log.v("IO Exception", e.getMessage());
}
}
But this approach is not much recommended though.
I agree with WareNinja- the SharedPreferences data areas would be sufficient for simple, non-relational data. This SO answer is very comprehensive in describing the nuances of implementing Activity and/or application-wide SharedPreferences.
The SharedPreferences framework will take care of all the data persistence minimising the amount of code you will need to write and your exposure to db-like 'update' transactions.
However be aware, in terms of expanding your application this medium is powerful but inflexible. The minute you feel the need to expand the type of data being stored move to SQLite or similar.
I suggest using SharedPreferences and/or memdiskcache, both works fast and seamlessly.
p.s. nothing against using sqlite, however i always try to avoid using db for client apps.
example lib to abstract local storage (no db!);
https://github.com/wareninja/generic-store-for-android
you can store and retrieve any type of data in key-value form,
sample code for loading java object from memdiskcache;
String keyPrefix = "blabla1";
if (GenericStore.isCustomKeyExist(GenericStore.TYPE_MEMDISKCACHE, keyPrefix, this)) {
mNewPoiDataList = (NewPoiDataList)GenericStore.getObject(GenericStore.TYPE_MEMDISKCACHE
, keyPrefix, this);
}

store Array in sharedpreferences

I have an Array with integer values. It will grow over time. It will have approximately up to 50 values.
I want to store the array persistent and thus I thought about storing it in SharedPreferences.
I know that no complex types can be stored in it, but I also heard about to serialise the Array and then store it in SharedPreferences.
Can someone give me a hint or even better sample code how to do that?
Not very efficient way, but will get the job done:
SharedPreferences prefs = ...;
final int count = 50;
final String KEY_COUNT = "COUNT";
final String KEY_VAL_PREFIX = "VAL_";
int values[] = new int[count];
/*
* ... put some stuff in values[] ...
*/
final Editor sped = prefs.edit();
sped.putInt(KEY_COUNT, count);
for (int i = 0; i < count; i++)
{
sped.putInt(KEY_VAL_PREFIX + i, values[i]);
}
sped.commit();
Then later you can retrieve these values by grabbing the KEY_COUNT value from the prefs, then filling your empty array with values2[i] = getInt(KEY_VAL_PREFIX + i, 0) calls.
You may use ObjectSerializer to do it. Here is SO discussion on how to do.Store Shared preferences
I would convert your array to a string of values separated by commas. And then store the string as a single key-value pair.
Then, when you want to extract the array, simple use the split function to split the string up into array elements based on a comma separator.

Using Shared Preferences with arrays

EDIT:
OK It turns out this code was working (more or less) I'd left in a line that reset the booleans I was trying to change. Thanks everyone for the help though.
Having trouble using SharedPreferences to read in saved array data when my app starts.
My _dPad Boolean and my _FreePlay Integer loads, saves and passes to and from my _renderer without any problems.
The trouble starts when I try and use some arrays
easteregg[] only has 2 entries right now so obviously I could just just turn them into separate variables but I wish to add more arras of longer length so this makes a convenient test example.
I've noted on the code what appears to happen (the easteregg[] settings just doesn't appear to have changed)
to read data:
// Read saved preferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
_renderer._dPad = prefs.getBoolean("_dPad", false); // * works ok *
_renderer._FreePlay = prefs.getInt("_FreePlay", 1); // * works ok *
_renderer.easteregg[0] = prefs.getBoolean("easteregg[0]", false ); // * not working
_renderer.easteregg[1] = true; // * even this is not working
setRenderer(_renderer);
to write data:
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
// As good a time as any to save current config
save = false ; // don't commit if nothing changed.
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = prefs.edit();
if (_renderer._dPad != prefs.getBoolean("_dPad",false)){ save = true ;
editor.putBoolean("_dPad", _renderer._dPad);}
if (_renderer._FreePlay != prefs.getInt("_FreePlay",1)){ save = true ;
editor.putInt("_FreePlay", _renderer._FreePlay);}
editor.putBoolean("easteregg[0]", _renderer.easteregg[0]);
editor.putBoolean("easteregg[1]", _renderer.easteregg[1]);
if (save == true){editor.commit();}
}
And in the .renderer class
// START SAVE DATA
public boolean _dPad ; // false no Virtual Pad *Works Fine*
public int _FreePlay ; // 1 = no free play *Works Fine*
public boolean[] easteregg = new boolean[2]; *Values don't load or save*
//public boolean easteregg[]; // tried this first *CAUSES CRASH*
// END SAVE DATA
Do I have to convert the arrays to strings? I don't get how to change them.
I put your code into a quick activity, creating just the shell of the renderer class as you have above and found that your save boolean is false, so it never commits the preferences.
I forced the save to true, and played around with it and everything worked fine from there.
I'd recommend adding checks to the easter eggs the same as you have for any other preference; test to see if the current value is the same as the saved value, and if not, set the save flag.
I would suggest saving the array as a string in a single variable. It appears you have an array of booleans. So loop through it to make it a series of either ints (0, 1) or the string "true" or "false" then save it to an int or string.
I suspect the probelm might be that your setting name contains square brackets. I think that in key value names, the key name must be a valid variable name. And square brackets are not allowed in variable names.
However i would also expect this to throw an error. Does the code work if you name you settings "easteregg_01" and "easteregg_02"?
The best solutions would be to convert your array into JSON string and store it as preference value. If you have small amount of data, you can as well stick with org.json classes provided by android. If you have more data, GSON pull parser would be better, as it utlizes pull parser. And if you are really lazy, you grab my small databinding library and do:
String jsonState = preferences.getString(GAME_STATE, null);
StateStorage storage = JSONUnmarshaller.unmarshall(new JsonReader(new
StringReader(jsonState)), StateStorage.class);
and it will instantiate java class for you and fill in the data. And to save:
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
StringWriter writer = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(writer);
JSONMarshaller.marshall(jsonWriter, ss);
editor.putString(GAME_STATE, writer.toString());
editor.commit();
Databinding library is available on github, or from maven central:
https://github.com/ko5tik/jsonserializer
PS: at the moment I work on injection of preference values ( at the moment primitives only):
https://github.com/ko5tik/andject

Categories

Resources