Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a list of longitude and longitude points in an xml file that is used throughout my application. I find my self repeating this code to get points often and think there must be a better way?

    String[] mTempArray = getResources().getStringArray(R.array.stations);
    int len = mTempArray.length;
    mStationArray = new ArrayList<Station>();
    for(int i = 0; i < len; i++){
        Station s = new Station();
        String[] fields = mTempArray[i].split("[\t ]");
        s.setValuesFromArray(fields);
        Log.i("ADD STATION", ""+s);
        mStationArray.add(s);
    }

XML is in the format of:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="stations">
        <item>
            <name>Station name</name>
            <longitude>1111111</longitude>
            <latitude>11111</latitude>
            <code>1</code>
        </item>

And another (possible) problem is that to get just one station I have to get all of them and pull the one I want from the array. Is this going to be considerably slower? Can I make this array consistent throughout the app? (But keeping the separate Intent methodology)

share|improve this question

3 Answers

up vote 2 down vote accepted

I had the same thought as MilkJug, to use a utility method to create the stations, but I want to offer a slightly different approach: Move as much of the construction logic as possible into the Station class constructor. To keep the example simple, I'm moving the utility method into the Station class as well.

This provides an overall cleaner design, as outside of the Station class itself, your code should never have to deal with a Station object whose construction/initialization steps haven't been fully completed.

(kgiannakakis's suggestion to use a database may be a better way to go if you have a lot of Station objects.)

public class Station {
    private static List<Station> sStationArray = null;

    /**
     * Construct a Station from a specially-encoded String. The String
     * must have all the necessary values for the Station, separated by tabs.
     */ 
    public Station(String fieldString) {
        String[] fields = fieldString.split("[\t ]");

        // For safety, setValuesFromArray() should be declared 'final'.
        // Better yet, you could just move its body into this constructor.
        setValuesFromArray(fields);

        // I'm assuming 'mName' is the name field for the Station
        Log.i("Station", this.mName);
    }

    public static Station getStationArray(Context ctx) {
        if (sStationArray == null) {

            // (Please don't use the prefix 'm' for non-member variables!)
            final String[] tempArray = 
                ctx.getResources().getStringArray(R.array.stations);
            final int len = tempArray.length;

            // Passing the length into the ArrayList constructor (if it's
            // known, or can be guessed at) can be a very simple yet
            // effective optimization. In this case the performance boost
            // will almost certainly **not** be meaningful, but it's
            // helpful to be aware of it.
            sStationArray = new ArrayList<Station>(len);    

            for (int i = 0; i < len; i++) {
                Station s = new Station(tempArray[i]);
                sStationArray.add(s);
            }
        }
        return sStationArray;
    }
}
share|improve this answer
Thanks for this. Would it matter if I changed it to an ArrayList? – Ashley Jan 14 '11 at 18:18
It's already an ArrayList -- see the line sStationArray = new ArrayList<Station>(len);. You could change sStationArray to be of type ArrayList<Station>, but that would not make any difference in functionality or performance. – Dan Breslau Jan 14 '11 at 19:24

Why not create a utility method that takes a context as a parameter and returns the station resources? For example:

public class StatUtil {
   private static List<Station> mStationArray = null;

   public static Station getStation(Context ctx) {
    if (mStationArray == null) {
      String[] mTempArray = getResources().getStringArray(R.array.stations);
      int len = mTempArray.length;
      mStationArray = new ArrayList<Station>();
      for(int i = 0; i < len; i++){
        Station s = new Station();
        String[] fields = mTempArray[i].split("[\t ]");
        s.setValuesFromArray(fields);
        Log.i("ADD STATION", ""+s);
        mStationArray.add(s);
      }
    }

    return mStationArray;
  }
}

and call it from your code with:

stationArray = StatUtil.getStation(this);

Repeatedly fetching the stations will be slower than caching them, but not significantly slower unless you are fetching them in a loop. Doing as above will prevent multiple copies from being fetched.

share|improve this answer
The call to getResources() needs to be prefixed with ctx. – Dan Breslau Jan 14 '11 at 16:52

I could propose two solutions:

  1. You could create a Singleton class that initializes once, reads the data from the XML and stores the stations in a List or a Map. Use a Map if you want to quickly find a station based on its name. The Singleton class will provide methods for retrieving all stations or just one of them.
  2. Create a database table and store the information there. You may need more code, but the advantage will be that you will be able to run more advanced queries.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.