Guided Tour
- May 10th, 2010
- Write comment
My final project! It’s long, and I covered a lot of the interesting parts in the MapView and GPS examples.
I want to start by outlining my biggest regret in regards to my application architecture so I can spend the rest of this post explaining how awesome my program is. This is my first time programming for a mobile device and my first real experience with Java. Unlike with C++, where I can comfortably create elaborate class hierarchies and argue the merits of Hungarian notation, I began this program with zero knowledge of Java and Android “best practices.”
So, when I was researching dialog creation for displaying landmark information, I researched best practices for dialogs. One COULD just instantiate a dialog class, and manually bind it to your application’s context, but my text implied it would be better to use the View class’s built-in callback function:
protected Dialog onCreateDialog(int id)
The function is called by the Android operating system when a particular dialog is requested, and returns the code needed to build the dialog:
protected Dialog onCreateDialog(int id) { switch(id) { case COFRIN_DIALOG: return mMarkers.getDialog("Cofrin Hall"); ... }
Pretty simple, right? Actually instantiating a dialog using this callback looks like this:
showDialog(_index);
where “_index” was the position in the list of landmarks the user touched. Couldn’t be simpler, right?
Wrong! I thought I was doing dialogs the “right” way, and at first blush this code seems fairly elegant. The only problem is that this callback method is wholly owned by our application’s main View class. And this class doesn’t have (direct) access to the same data that the MapView class does (as the MapView class owns the landmarks and points of interest.)
Had I started the project knowing what I know now, I would have disregarded the recommendations on Google’s Android site and in my text and just create a separate Dialog class. Another class could have had sole ownership of the data, and all of my Views (and the dialog class) could communicate through the Data class.
I covered most of the interesting bits in previous posts, namely the MapView code and the GPS code. However, I made my GPS code more robust by asking for the “best” location service that was available (and turned on!) rather than just assuming a GPS like in the demo code:
Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); //Pretty much means GPS. "Fine" accuracy means stalker-approved proximity. criteria.setAltitudeRequired(false); //We don't need an altimeter criteria.setBearingRequired(false); //We don't really need to know which direction you're facing criteria.setCostAllowed(true); //Some cell companies charge for GPS use?! Bastards. There's a ring for them a few floors up from popes and usurers. criteria.setPowerRequirement(Criteria.NO_REQUIREMENT); //All the examples had POWER_LOW, but I care more about it finding the GPS hardware than battery life //Summon forth a location provider that matches our requirements! (And is on!) mProvider = mLocationManager.getBestProvider(criteria, true);
The “guided tour” part was actually fairly simple to implement. I have two parallel arrays of destinations and descriptions, and an index of how far you’ve progressed in the tour:
private static int mTourState = 0; private static String[] mTourStops = { "Cofrin Hall", "Todd Wehr Hall", "Boyle Hall", "Bemis International Center", "Mulva Library", "Campus Center" }; private static String[] mTourCaptions = { "First stop is Cofrin Hall!", //Cofrin "Now go to Todd Wehr Hall!", //Todd "Now some meaningful and descriptive way of telling you to go to Boyle!", //Boyle "Now go to the Bemis International Center!", //Bemis "Now go to the Mulva Library!", //Mulva "Now go to the Campus Center!" //Campus Center };
I have a ProximityListener that fires when a user reaches a particular destination. They the advance to the next point on tour automagically. These worked reliably during testing wandering about campus, but the version 1.5 of the Android SDK seemed to be missing some features in the newer 2.0 and 2.1 incarnations.
public ProximityHandler(TabbedMaps parent) { mParent = parent; } @Override public void onReceive(Context context, Intent intent) { //Will be true if they are ENTERING the target radius around the next building on the tour //But seems to only be present on Android version 2.0 and above; phone uses 1.5 //Boolean entering = intent.getBooleanExtra("com.vromtr.tourproximity", false); Boolean entering = true; if (entering) { //Advance to the next part of the tour mParent.tourGoForward(); } } }
The rest of my code is about 50% comments by volume. It was definitely a learning experience for me – I got to learn a new SDK in a new language in a new IDE targeting a new platform. So, most of the comments were written for myself as I was learning. But, they should be helpful for whoever might inherit a similar project in the future.