|
Design
Foursquare for Android DesignFoursquare for Android split into two components; the API (com.joelapenna.foursquare) and the Android frontend (com.joelapenna.foursquared). The API is based off the foursquare beta API, available at http://groups.google.com/group/foursquare-api/web/api-documentation. Foursquare APIThe foursquare API is documented at http://groups.google.com/group/foursquare-api/web/api-documentation The API itself is split into several key components based on the separation between document parsing, and http serving. In com.joelapenna.foursquare.http you will find the http client code used to acutally make requests to foursquare.com. com.joelapenna.foursquare.parsers contains xml parsers and com.joelapenna.foursquare.types contains java classes to represent the parsed XML. HTTPThe foursquare http client is synchronous but supports multithreaded access. This api supports basic and oauth based authentication and can be enabled or disabled using the Foursquare client's useOAuth constructor parameter. The client is single-user only in that it is not out of the box able to support http requests from multiple simultaneous users. The network protocol used to make requests to foursquare.com is HTTP. Requests go to URLs such as http://api.foursquare.com/api/v1/venues with the url query defining passed parameters such as http://api.foursquare.com/api/v1/venues?limit=10. The foursquare api returns data in XML, examples of which are in /captures/api/v1 and outlined in the canonical api documents. The ability to debug HTTP operations can be controlled by the FoursquaredSettings constant API_DEBUG. After an http request is completed, the retrieved XML is passed to a parser. (See #Parsers) ParsersThe XML returned by the foursquare servers follow a very simple schema, simply speaking that any attribute on a foursquare object is represented by an XML tag with the child being its value. <username>jlapenna</username> <badges> <badge /> <badge /> </badges> There is no common annotation in the returned XML to determine if an object has a list of properties or if it is a list of values in one common attribute (eg, if the foursquare object lists a series of attributes or if it has one attribute with multiple values) aside from explict examination. The xml type samples in captures/types/v1 describe the contents of each element for every supported foursquare type. AbstractParserAbstractParser is the base class used to construct any datatype parser. It is based on the XmlPullParser parsing strategy and API. It is designed to skip elements it does not understand, it will also throw a =FoursquareException= whenever it encounters an <error> stanza. It is necessary to implement a parser that extends AbstractParser for any xml element that can be encountered during the xml parse. It is expected and likely that a parser will support a "root" xml element and its child values, constructing using other parsers to understand its child attributes. TypesThe foursquare API constructs collections of objects as Groups which simply extend java's List. A Group may contain multiple groups or other FoursquareTypes. A Group also possesses a "type" which describes the contents of the Group. Each type is autogenerated using a pair of python scripts that parse some example xml files. See #util/generate.py Foursquare.javaThis is the main access point for the foursquare API, abstracting and hiding both the HTTP and XML subcomponents of the framework. Its usage is pretty clear and can be clearly understood from the method names and associated official documentation. Foursquared (The Android Client)The general architecture of the Foursquare Android client is centered around various resource managers and clients stored in the "almost" global Application context. It is global in the sense that any Activity or Service can latch onto the Application context with getApplication, cast it to a Foursquared instance and access the various components and methods available on the Foursquared object. (Note Foursquared not Foursquare. "d" denotes the android side of things). TaskHandlerThe TaskHandler is responsible for doing asynchronous operations in the applicatation that don't have a specific Activity context assocated with it, for example, when updating a users's foursquare city when they move. See #CityLocationListener. GeolocationFoursquared depends on two LocationListeners which attach themselves to various android LocationProviders. Each is based on capturing the "best" location where "best" is defined as "mostly accurate and mostly recent." CityLocationListenerThis listener is registered to the LocationManager only when the user is "logged in" to foursquare. It attaches itself to a "COARSE_LOCATION" provider and upon great location change, will attempt to have the application /switchcity to whatever location the user has just moved to. BestLocationListenerThis location listener will register itself with /every/ LocationProvider the LocationManager supports. It can be manually registered and unregistered by application components such as Activitys or Services. The BestLocationListener supports two access interfaces. It supports an "Observable" interface that will notify on /best/ location updates as well as a getBestKnownLocation method that will return the same information. The /best/ location is calculated based on update time and accuracy. The listener registeres with GPS, network and possibly other providers. As it recieves updates via the standard LocationManager.requestLocationUpdates, it determines if the update it recieved most recently is (first) actually more recent than its last location update and then if it is more accurate than the previous update. This way it is harder for an out of date GPS location to override a recent-but-less-accurate wifi triangulation or for a very accurate but a slightly old GPS update to be upsurped by a wildly inaccurate but to-the-second network location update. RemoteResourceManagerOften in the course of constructing a view in the application, we need to request things like images from remote servers. An example: user profile photos. To do this we've implemented an asynchronous, multi-threaded http client that will fetch resources, store them to disk, and provide InputStream and File access to the requested objects. The API also allows you to register as an Observer to recieve updates /whenever/ a remote resource request is completed. Lastly, the RemoteResourceManager provides an ability to cleanly shutdown and wipe the cache used in order to reclaim disk space. CaveatsoAuth is disabled right now in the foursquare UI as I don't think their oAuth "auth_exchange" protocol is reliable and my implementation isn't very good. Toolsutil/oget.pyHTTP client with oAuth support, just create a file like this in ~/.oget: CONSUMER_KEY CONSUMER_KEY_SECRET USERNAME PASSWORD It works by authenticating with a consumer key/secret to get a client token, stores that in this file, then retrieves a page. oget 'http://api.foursquare.com/v1/venues' This actually stopped working after a backend upgrade. Try using curl -u user:password 'http://...' instead. util/gen_class.pyGenerate the java class for a particular foursquare datatype. gen_class.py ../captures/types/v1/didyoumean.xml > ../main/src/com/joelapenna/foursquare/types/Didyoumean.java util/gen_parser.pyGenerate the parser for a particular foursquare datatype. ./gen_parser.py ../captures/types/v1/checkin_result.xml > ../main/src/com/joelapenna/foursquare/parsers/CheckinResultParser.java util/generate.pyGenerate the parser and .java files for all examples in captures/types/v1 generate.py Both util/gen_class.py and util/gen_parser.py use the templates defined in captures/types/v1, these files are annotated 1-dimensional versions of the xml streams returned by the official API. Each script will read the xml and construct an internal representation of what the xml is describing. Each xml tag in the capture may have a type attribute which is a hint to the generators of the target java type (and parser) that the tag represents. For example: <?xml version="1.0" ?>
<user>
<id>9711</id>
<checkin type="Checkin"></checkin>
<badges type="Group">
<badge type="Badge"></badge>
</badges>
</user>This shows that the User java object will have two attributes protected by getters and setters. The abstract version of this class would look like: class User implements FoursquareType {
abstract public String getId();
abstract public void setId(String id);
abstract public Checkin getCheckin();
abstract public void setCheckin(Checkin checkin);
abstract public Group<Badge> getBadges();
abstract public void setBadges(Group<Badge> badges);As <id> does not list a type, it defaults to a string. |
Do you have any API documentation or examples for using this?
Hi Joe, what are the possibilities of having an option to automatically check-in locations during a day?
I second subrajesh's question. This really needs documentation.
Is there any way to make the app more efficient? I am running Motorola Droid Bluebery Froyo, and it is the only app that lags. Maybe reduce some of the code that is not necessary, if any? Otherwise, I like that you can post pics, and share with other socNet sites.
Please give me any short and simple example of this API.