2

I'd like to know a better approach to improve performance of my program. The objective is to load resources automatically, I'm using names of string or string-array elements. For example, if I have the next resources:

<string name="temperature">temperature</string>
<string name="pressure">pressure</string>
<string name="velocity">velocity</string>
...

<string-array name="measures">
    <item>@string/temperature</item>
    <item>@string/pressure</item>
    <item>@string/velocity</item>
    ...
</string-array>

<string name="name_temperature">Temperature</string>
<string name="name_pressure">Pressure</string>
<string name="name_velocity">Velocity</string>
...

<string-array
    name="name_measures">
    <item>@string/name_temperature</item>
    <item>@string/name_pressure</item>
    <item>@string/name_velocity</item>
    ...
</string-array>

<string-array name="units_temperature">
    <item>K</item>
    <item>°C</item>
    <item>°F</item>
    <item>R</item>
</string-array>

I'm loading resources this way:

measuresMap = new HashMap<String, String>();

String[] measures = getResources().getStringArray(R.array.measures);

for(int i = 0; i < measures.length; i++){
    measuresMap.put(measures[i], getResources().getString(getResources().getIdentifier("name_" + measures[i], "string", getActivity().getPackageName())).toString());
}

i.e. I'm mapping the string-array values from 'measures' to it's corresponding string 'name_<>'.

I'm using a Spinner to select the measure, for example, 'Temperature':

measureSpinner = (Spinner) view.findViewById( R.id.spinnerConverter );
setSpinner(measureSpinner, R.array.name_measures, android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_dropdown_item);

When an item is selected, a method retrieves the key from the Map depending on the item's string of the Spinner (getKeyByValueFromMap from here):

String[] units = getResources().getStringArray(getResources().getIdentifier("units_" + getKeyByValueFromMap(measuresMap, measureSpinner.getSelectedItem().toString()), "array", getActivity().getPackageName()));

public <T, E> T getKeyByValueFromMap(Map<T, E> map, E value) {
    for (Map.Entry<T, E> entry : map.entrySet()) {
        if (value.equals(entry.getValue())) {
            return entry.getKey();
        }
    }
    return null;
}

I need to do this to populate a NumberPicker:

String[] units = getResources().getStringArray(getResources().getIdentifier("units_" + getKeyByValueFromMap(measuresMap, measureSpinner.getSelectedItem().toString()), "array", getActivity().getPackageName()));

I think this is somehow inefficient. I read something about loading arrays with a TypedArray. I thought of a multidimensional String array. The objective is the same: load resources automatically (driven by the for loop to populate the Map). Is a HashMap the best option? It would be easier if a resource name could be defined with another resource string:

<string name="@string/temp">Temperature</string>
Community
  • 1
  • 1
Mario
  • 486
  • 4
  • 7

1 Answers1

1

Every time I read a question about performance, a bell rings in my mind asking if there is really a performance issue. If you work with a small quantity of values, you won't really notice any bad performance. And if you work with lots of data, you should probably use sqlite instead.

If you won't be using @string/name_temperature per se, it can go directly on the array and make it similar to the example on the documentation

And yes, you can make use of TypedArray:

TypedArray measures = context.getResources().obtainTypedArray(R.array.name_measures);

It understands length() and getString(index).

Back to your code, I don't really understand your need of a map here, unless you are really worried of putting the strings directly in your arrays instead of the IDs.

Also, I see you use the name to generate the id of the Spinner; in this context, it doesn't help the performance and, more important, it does not make the code clearer either.

So the real answer: I would take the references to the Spinners somewhere accessible. It might be nice to reify the need of a different key, and make a sublclass of Spinner that can convert indexed positions to the strings I want. In other words, delegate to the Spinner the responsibility of storing and converting positions to strings.

Since here I do need to map positions to the strings (instead of just the IDs), I could use a simple String[] and then, onItemSelected just access the position, geting the desired String, or setting it as selected (then when you ask your Spinner which value it has, you can just ask for its selected value, remember you now have it's reference on some attribute).

Logain
  • 4,259
  • 1
  • 23
  • 32