views:

213

answers:

3

I've started working on some Android applications and have a question regarding how people normally deal with situations where you have a static data set and have an application where that data is needed in memory as one of the standard java collections or as an array.

In my current specific issue i have a spreadsheet with some pre-calculated data. It consists of ~100 rows and 3 columns. 1 Column is a string, 1 column is a float, 1 column is an integer. I need access to this data as an array in java.

It seems like i could:

1) Encode in XML - This would be cpu intensive to decode in my experience.

2) build into SQLite database - seems like a lot of overhead for static access to data i only need array style access to in ram.

3) Build into binary blob and read in. (never done this in java, i miss void *)

4) Build a python script to take the CSV version of my data and spit out a java function that adds the values to my desired structure with hard coded values.

5) Store a string array via androids resource mechanism and compute the other 2 columns on application load. In my case the computation would require a lot of calls to Math.log, Math.pow and Math.floor which i'd rather not have to do for load time and battery usage reasons.

I mostly work in low power embedded applications in C and as such #4 is what i'm used to doing in these situations.

It just seems like it should be far easier to gain access to static data structures in java/android.

Perhaps I'm just being too battery usage conscious and in my single case i imagine the answer is that it doesn't matter much, but if every application took that stance it could begin to matter.

What approaches do people usually take in this situation? Anything I missed?

+2  A: 

I'd go #4, if you're sure this needs to be in memory all of the time. Other options include JSON, a Thrift-encoded data structure, or a Protocol Buffers-encoded data structure.

CommonsWare
This is what i assumed would be the correct answer, although i was hoping for some automation of the process on this level of SDK/device. For reference this approach loads an ArrayList with my data (my storage class is slightly more complicated than alex's) in 1ms on a Nexus One with some background tasks running, i assume the real timing is <1ms making it many times more battery efficient.
Mark
+3  A: 

I'd go a modified #5:

strings.xml:

<string-array name="some_data">
    <item>string|0.56|100</item>
</string-array>

Parser.java:

String[] arr = getResources().getStringArray(R.array.some_data);
for (String str : arr) {
    string[] columns = str.split("|");
    // to Java objects or parallel arrays
}

Microbenchmark:

<string-array name="data">
    <item>some0|10|1.0</item>
    ...
    <item>some99|199|1.99</item>
</string-array>

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        long start = System.currentTimeMillis();
        String[] arr = getResources().getStringArray(R.array.data);
        ArrayList<Triple> triples = new ArrayList<Triple>();
        for (String s : arr) {
            String[] parts = s.split("\\|");
            Triple tr = new Triple();
            tr.str = parts[0];
            tr.i = Integer.valueOf(parts[1]);
            tr.f = Float.valueOf(parts[2]);
            triples.add(tr);
        }
        System.out.println(System.currentTimeMillis() - start);
        return true;
    }

    static class Triple {
        public String str;
        public int i;
        public float f;
    }

05-02 21:17:50.418: INFO/System.out(609): 125
05-02 21:17:51.128: INFO/System.out(609): 124
05-02 21:17:52.368: INFO/System.out(609): 124
05-02 21:17:53.158: INFO/System.out(609): 127
05-02 21:17:53.858: INFO/System.out(609): 123
05-02 21:17:54.688: INFO/System.out(609): 124
05-02 21:17:55.778: DEBUG/dalvikvm(609): GC freed 14380 objects / 525008 bytes in 136ms

On a 1.6 ADP1.

alex
One advantage of this approach over my suggestion is that it uses the resource system, so if the data changes based on device criteria (e.g., language for the string), you can take advantage of it. One disadvantage is parsing time, though for only ~100 rows that's probably not going to be a big problem. Also a slight disadvantage for memory allocations and garbage collection, but if this is only done once up front, that too shouldn't be a big deal.
CommonsWare
@Mark Glad you like it. :)
alex
+1  A: 

For (3) you can use an ObjectInputStream contructed from a FileInputStream (see the class-level Javadoc for some copy+paste code) to deserialize your Object(s) from the binary data stored in a file.

To create a binary file, use an ObjectOutputStream and a FileOutputStream similarly.

Nicholas White
I'd be a little careful about assuming that serialization works across architectures. Remember that Android does not run the Sun/Oracle Java VM, but the Dalvik VM.
CommonsWare
It works but in its current state in dalvik it is unfortunately horrendously slow.
Mark