I am currently storing game data such as a sequence of moves in a multi-dimensional array, that is defined as:
private final int[][] gameMoves = {{1},{2},{0},{3},{1,4},{1,4,5},{2,4}}
The array is of course much bigger.
I feel that there should be a more elegant way to do this, possibly storing the data separately from the code using either an XML file or the SQLite database and then retrieving it in a while-loop.
If using an XML file, what would be the format and what would be the method of retrieval?
If using an SQLite database, what would be the way to get the data inside the database before executing the source code?
Any examples would be much appreciated.
If this is data that never gets changed, there isn't really any reason to persist it, especially if it gets read from frequently, since you'll be taking a performance hit in the reading thereof. If anything, perhaps a separate package containing game data objects each providing 'gameMoves', might be a winner.
Or, if you're tied to the separation from a conceptual and/or requirement standpoint, JSON might be a good way to go, as it's more directly tied to multidimensional arrays than a XML file might be, and certainly easier to work with for that than a DB.
for example, your JSON file might be:
[1, 2, 3, [45, 6, 7], 8, [9, 10]]
You could then use the JSON library to parse it with minimal fuss:
JSONArray data = new JSONArray(textFromFile);
for(i = 0; i < data.length; ++i) {
//Read data
}
See http://developer.android.com/reference/org/json/JSONArray.html
If those numbers represent moves you should use constants.
const int MOVE_WAIT= 0;
const int MOVE_LEFT= 1;
const int MOVE_RIGHT = 2;
const int MOVE_UP = 3;
const int MOVE_DOWN = 4;
const int[] SHOOORYUKEN = {MOVE_RIGHT, MOVE_DOWN, MOVE_RIGHT};
int[][] gameMoves = {{MOVE_LEFT},{MOVE_RIGHT},{MOVE_WAIT},{MOVE_UP},SHOOORYUKEN}
etc...
Related
I save chosen items into shared preference, but as the user during runtime get to remove any of these items (from any position), and as I use the saved size (in the code below) to loop through the items, and here's the problem
Say I have 5 items ( item_1 - item_2 - item_3 - item_4 - item_5 )
if the user removed item_2 I update chosen_items_size to be 4 and I remove item_2 from the shared preference.
but when I load the items later I use the (size = which is 4 now), which as in the code below will miss item_5, how to fix this, any suggestions or better approach to achieve what I need?
mSharedPreference = getSharedPreferences("chosen_items", MODE_PRIVATE);
int size = mSharedPreference.getInt("chosen_items_size", 0);
for(int i = 1; i <= size; i++) {
mSharedPreference.getString("item_" + i, null);
}
Knowing that I want to enable drag and drop items, which using the above approach will make it pretty hard (if possible in the first place) to accomplish, any better approach to save & retrieve data / items?
Thank you
If you have a small amount of strings you can store them in one delimited string in SharedPreferences like so. You could also associate some metadata with each item and delimit that too.
You could utilize a built in SQL lite database.
Is this data that must persist between sessions? if not store it locally with a class and static variables/arrays.
I am in no way a seasoned programmer. I have been successful at getting AudioRecord to write microphone data directly to file (as a readable .wav file) as it comes in from the mic, with the help of many code snippets from the internet.
However, for what I want to do with my app, I need to save only portions of what comes in from the mic, and I thought I would be able to do that by saving the byte data into some sort of an array first so I could selectively use what I want and save to file. Like many examples do, my class for reading microphone data reads the data into a byte array defined as:
byte data[] = new byte[audioBuffer];
and is read in with
read = audio.read(data, 0, audioBuffer);
My idea was to save each byte data array after it is read in to some sort of another array, and then read back each individual byte data array later to save to file when the user requests it. I tried an ArrayList to hold the data arrays:
private ArrayList<byte[]> grabArray = new ArrayList<byte[]>(grabArraySize);
but I am apparently only getting the last byte data array from the microphone for the whole .wav file. I am guessing I am misusing the ArrayList, but it's description sounded like the best chance of being able to do what I need. I have tried to find another way to do what I want including ByteBuffer, but that does not seem to provide the type of control that an array provides, where I can overwrite old data with new, and then at any point retrieve any or all of the data.
Basically, I know how to do this if it were simple primitives like integers or floats, but byte arrays are apparently throwing me for a loop. On top of that, there is a byte primitive, then there is the Byte class which can be wrapper... all a bunch of ??? to someone who doesn't make a living programming in Java. What is the best way to manhandle byte arrays (or just bytes for that matter) like you would do with just plain numbers?
Some more code to show how I save the audio data (in my AudioRecord thread) to a temporary holding array, then try to retrieve the data (in another class) so I can save to file: (My code is a big mess right now with comments and me trying various methods, commenting out things I'm not currently using... it would be too much to put it all here and I don't have the time to clean it up. I'm hoping this description of how I am trying to handle byte arrays will be enough to the help I need.)
Reading audio data and saving to my temporary holding array:
while(recordState){
read = audio.read(data, 0, audioBuffer);
if(AudioRecord.ERROR_INVALID_OPERATION != read){
if(i_read == grabArraySize){
i_read = 0; // reset index to 0 if hit end of array size
}
grabArray.set(i_read, data);
i_read += 1;
}
}
When asked to, reading audio data back from temporary holding array so I can save to file:
while(i < grabArraySize - 1){ // not writing the whole array - leaving out the last chunk
if(i_write == grabArraySize){
i_write = 0;
}
os.write(tempArray.get(i_write));
i += 1;
i_write += 1;
}
My FileOutputStream os works fine - I am successfully writing to file with the .wav header. I need to figure out how to store the data[ ] byte arrays from the AudioRecorder somewhere other than directly to a file, so that I can then retrieve them whenever I want, and then write them to file. I am successfully getting audio data, but the whole file is repeating one piece of that audio data (of size audiobuffer) over and over into whole file. The file is the correct length; everything else seems to be working; I can even recognize the sound I was making in the little bit that gets saves over and over...
Update again - It appears that ArrayLists are just pointers, as opposed to holding values like a normal array of values. I am now defining grabArray and tempArray both as byte[ ][ ]. Example - if I want to hold 10 separate byte arrays, with each byte array of size audioBuffer, I would define my array as such:
byte[][] grabArray = new byte[10][audioBuffer];
Now, in my AudioRecord thread, I am looping through my grabArray, setting each index = to the incoming audio byte array:
grabArray[i] = data;
Then, when I'm ready to write out to file, (after setting tempArray = grabArray ; I do this in case the AudioRecord thread writes a new audio chunk to the grabArray before I get to write to file) I loop through my tempArray:
os.write(tempArray[i]);
I am still getting only one instance of data[ ] (the audio chunks) repeated all throughout the file. Am I at least on the right track?
My application records user movement with Geofence boundaries, if the user exits the Geofence, alerts are appropriately escalated. These alert are counted and displayed in a summary at the end of the activity. However I would like to create a stats page where it displays the last week or month of activities as well as the number of alerts so that I can display these in a chart. Is there anyway to do this effectively without using a database?
I had thought of writing data to a log file and reading it but curious as to if there is a better option.
You can use SharedPreferences but it will require a lot of controls, probably more then creating a database. If you insist not to use a database, put an integer to your shared preferences saving the count of your data, also that integer will become your id. Then you can store your data with a loop depending on your data.
Here is to write your data to shared preferences
SharedPreferences mSharedPrefs = getSharedPreferences("MyStoredData",
MODE_PRIVATE);
private SharedPreferences.Editor mPrefsEditor = mSharedPrefs.edit();
int count = mSharedPrefs.getInt("storedDataCount", 0);
for(int i = 0 ; i < yourCurrentDataCount ; i++) {
mPrefsEditor.putInt("data" + count, yourData.get(i));
count++;
}
mPrefsEditor.putInt("storedDataCount", count);
And to get your data,
int count = mSharedPrefs.getInt("storedDataCount", 0);
for(int i = 0 ; i < count ; i++) {
yourData.add(mSharedPrefs.getString("data" + i, "defaultData"));
count++;
}
Edit:
I should have added some explaining. The idea is to save the count of your data to generate an id, and save the tag according to it. This code will work like this, lets say you have 5 strings. Since you don't have a MyStoredData xml, it will get created. Then since you don't have the "storedDataCount" tag, you will get 0 as a count. Your loop will iterate 5 times and in each iteration, you will add a tag to your xml like "<.data0>your first data<./data0><.data1>your second data <./data1>... After your loop is done, you will modify your storedDataCount and it will become <.storedDataCount>5<./ storedDataCount>. And the next time you use your app, your count will start from 5 so your tag will start from <.data5>. For reading, you will iterate through tags by checking "data0", "data1" and so on.
You can use java serialization if you dont want to use database.
You can also use XML/JSON for storing data.
I support already mentioned favoritism towards using a DB for this task. Nevertheless, if I were to do it via FS, I would use a transactional async library like Square's tape is.
In your case I would keep the data during a session in JSON object (structure) and persist it (in onPause()) and restore it (in onRestore()) with tape's GSON Object Converter.
Should be easy out of the box, I believe.
Tape website: http://square.github.io/tape/
Alternatively to manually persisting a file or using a 3rd party library like tape, you could always (de)serialize your JSON to SharedPreferences.
I have a training set of images, for each of which I've detected and computed their feature vectors (using ORB feature descriptors and extractors. The questions is: since I need to save those features to reutilise them for matching against test images (using SVM classifier); what is the best way to store the feature vectors, locally on the Android device?
The feature vectors to be saved are of variable size per image, and are thus those with non-maximal sizes are padded with zeros to unify all vectors' sizes. The maximum size currently is 500 rows x 32 cols; thus 16k features.
here are the options I could reach so far;
I've heard of OpenCV's FileStorage, but when going through the java documentation, I noticed a save method for HOG features (not ORB). Furthermore, I'm not sure if saving features using OpenCV's file storage options would be most optimal memory-wise for Android phones, given that the xml file would be too large to load.
My current choice is to opt for a sqlLite database, having a table with two cols; id and feature (as frequently suggested online); to tabulate all the 16k features in sqlLite. That seems rather phone-storage intensive, but it's the most reasonable solution I can find.
Is there a common method to handling feature vectors on Android phones? Does it encompass any of the above methods; if not can you please offer some guidelines on how to implement such a storage solution?
Thank you.
In my opinion the most universal way to store the keypoints is to first convert them to a data-interchange format like JSON.
After you are able to do that conversion you have a lot of flexibility to store it. JSON is easily converted to a String and/or sent through a network connection.
With OpenCV C++ you are able to store data as YAML, but that is not available for Android yet.
To parse JSON in Java you can use this easy to use library Google GSON.
And here is my first attempt to do exactly that:
public static String keypointsToJson(MatOfKeyPoint mat){
if(mat!=null && !mat.empty()){
Gson gson = new Gson();
JsonArray jsonArr = new JsonArray();
KeyPoint[] array = mat.toArray();
for(int i=0; i<array.length; i++){
KeyPoint kp = array[i];
JsonObject obj = new JsonObject();
obj.addProperty("class_id", kp.class_id);
obj.addProperty("x", kp.pt.x);
obj.addProperty("y", kp.pt.y);
obj.addProperty("size", kp.size);
obj.addProperty("angle", kp.angle);
obj.addProperty("octave", kp.octave);
obj.addProperty("response", kp.response);
jsonArr.add(obj);
}
String json = gson.toJson(jsonArr);
return json;
}
return "{}";
}
public static MatOfKeyPoint keypointsFromJson(String json){
MatOfKeyPoint result = new MatOfKeyPoint();
JsonParser parser = new JsonParser();
JsonArray jsonArr = parser.parse(json).getAsJsonArray();
int size = jsonArr.size();
KeyPoint[] kpArray = new KeyPoint[size];
for(int i=0; i<size; i++){
KeyPoint kp = new KeyPoint();
JsonObject obj = (JsonObject) jsonArr.get(i);
Point point = new Point(
obj.get("x").getAsDouble(),
obj.get("y").getAsDouble()
);
kp.pt = point;
kp.class_id = obj.get("class_id").getAsInt();
kp.size = obj.get("size").getAsFloat();
kp.angle = obj.get("angle").getAsFloat();
kp.octave = obj.get("octave").getAsInt();
kp.response = obj.get("response").getAsFloat();
kpArray[i] = kp;
}
result.fromArray(kpArray);
return result;
}
I would suggest storing the feature vectors as images to have a simple and compact representation. You could even use non-destructive compression such as png to minimize file size.
I see that you have considered using the Android SQLite database:
My current choice is to opt for a sqlLite database, having a table with two cols; id and feature (as frequently suggested online); to tabulate all the 16k features in sqlLite. That seems rather phone-storage intensive, but it's the most reasonable solution I can find.
There is a way to save and retrieve MatOfKeyPoint to SQLite database with reasonable efficiency.
Using the database has the advantage of not needing to request write external storage permission from the user (although that permission might be needed for some other of your apps functions).
There is a complete Android solution, with Java code which can be found in this StackOverflow Answer.
The following is a description of what's going on in the code from that answer...
MatOfKeyPoint to byte[] and some attributes
To save to the database, you need to save to a byte[] object. Using the MatOfKeyPoint.get() method, you can get a populated float[]. Then using ByteBuffer.putFloat(), you can loop through all of your floats, finally getting a populated byte[] by using ByteBuffer.array().
You also need to save some attirbutes MatOfKeyPoint.rows(), MatOfKeyPoint.cols(), and MatOfKeyPoint.type() to your database, along with the blob of byte[].
Database blob (byte[]) to MatOfKeyPoint
To reconstitute your MatOfKeyPoint object from the database, first you make a float[] out of your blob. Use ByteBuffer.wrap(blob), then run ByteBuffer.asFloatBuffer(), and finally FloatBuffer.get() with a properly sized new float[].
Now that you have yourFloatArray you run MatOfKeyPoint.create(rows, cols, type), those three things coming from the database record. Finally you run MatOfKeyPoint.put(0, 0, yourFloatArray).
I'm trying to create a system to save the list of levels that have already been played in my application.
I've been using Editor and SharedPreferences to store information on the phone.
But now I have a list of int to save
I've been trying to figure out something with
DataOutputStream out;
//Size
int resultSize = results.size();
out.writeInt(resultSize);
//All the levels ID
for (int idx = 0; idx < resultSize; idx++){
//l().debug("Lvl ID: "+results.get(idx));
out.writeInt(results.get(idx));
}
But then I don't know how to store this in the shared preferences.
I'm also concerned about size, this list of ID might get really big so I want to optimize the amount stored.(hence the DataStream)
any ideas
Jason
You could iterate through your list and construct a comma delimitted String from the ints. E.g. "1,2,15..etc", then just write this string to SharedPreferences. You would obviously have to tokenize it when you read it back.
How big is "really big" exactly? Considering it's a list of levels played by a human I am going to assert that it is "small" for what a smartphone can handle. Though, personally I would recommend this to go in a SQLite table of "completed" levels for ease of querying the information.
I don't think that you need the most efficient way. This data is small, go with what you know. Pick something simple and understandable, something easy to debug.
A flat file with every level int on a new line. You can't get much simpler than that. Sure, it's bigger than the most efficient way, but it's much easier to recover from corrupted files, much easier to debug.
Binary stream is the most efficient way how to save integers. If you have really a lot of numbers (megabytes), use DataOutputStream combined with ZipOutputStream.