This the purpose of this app was to learn Java and Android, and to complete a challenge provided by a friend of mine (who I imagine some of you ESPNers may know). There is no possibility of commercial use. Note that all the team icons and player portraits use a dummy icon, and a lot of the data is also simply randomly inserted (full news stories, player positions, etc), as this data is not available in the free API. Some categories are wholly unimplemented (standings for example - as no access to this API is given with the free tier). The app is not by any stretch polished. There are edge cases that don't give good user feedback, though I don't any that cause crashes, there is a lot of logging that isn't necessary, and it isn't going to handle incoming calls, etc well.
I uploaded all the relevant project files to GitHub, and should be available to view or download at https://github.com/rollie42/SportsCenter/tree/master/SportsCenter/src/com/espn. A full list of screenshots can be seen at http://imgur.com/a/xFNHk. Note if you want to compile and run it, you will need to add your own API key to ESPNDataAccess.java; other than that it should run out of the box (more on the api key later). Okay, time to jump into a description.
There are 2 main aspects of the application - getting/working with data and displaying that data in an intuitive format. Almost all the work in the app occurs in the activity, ScoreCenterActivity.java (ignore the naming scheme), while most data access is done from separate threads using Java AsyncTasks, guaranteeing that the UI thread is never locked up waiting for an HTTP request to return.
The one exception to this occurs when we load the user's starting layout preference in the UI thread, as there's not much reason to hurry up with a UI with nothing to show, and we need to make sure it is loaded before other background threads are kicked off. Currently this is hard-coded to be "Baseball", "MLB", giving a start screen that looks something like http://i.imgur.com/dQdmH.png. Then we kick off 1 AsyncTask to load leages for each sport we have (which is also one of the few things hard-coded, just Baseball, Football, Soccer, and Basketball). Once these tasks are going, we call 'setActiveGroup' to assign the MLB group as active, which updates the UI appropriately.
This brings us to the concept of groups. In the main Activity class, all data is stored in a root node of class 'Grouping' called mSportsData. It has no group type, and stores groups of type SPORT. Groups of type SPORT store groups of type LEAGUE, which in turn store TEAMs, which store Players (the one data type that is not considered a Group). If we ever needed to maintain state data between executions of the app, it would be by storing/loading mSportsData.
When a user selects a team from the MLB screen, we simply call setActiveGroup, passing the appropriate group. setActiveGroup then adjusts the UI, and kicks off AsyncTasks to load the data. Note that those tasks update the UI when they finish in their onPostExecute method (which runs in the UI thread - the data threads never update the UI). To let the user know that data is loading in another thread, the first thing these AsyncTasks do is display a 'loading' icon which runs in the UI thread until the actual data can be loaded; you can see this by having the news roster tab open and switching teams, as it will take a second to load those teams.
The app as a whole is not tailored for the ESPN API. From the activity, data is loaded from the DataLoader, which in turn relies on one or more abstract DataAccess objects. The only current implementation for DataAccess is ESPNDataAccess, but it would be reasonably easy to use any other API provided you could implement the abstract methods of DataAccess. DataLoader provides it's own caching using a LinkedHashMap with a least recently used replacement strategy (only data that hasn't been requested recently will be removed to free up memory). ESPNDataAccess is built to handle the restrictions placed on the free API. It synchronizes HTTP requests for data, such that only 1 request can be going at once, so we don't hit the 1-query per second limit. Also, it provides the ability to have a 'prefix'. This was my own way of handling the API restrictions, and is a simple php page that caches query results in a database. If the user requests 'All players on the Indians', the php page will check the DB. If it finds the results, it returns them as a JSON message. If not, it uses php::curl to run the request given in the 'url' param. Assuming it succeeds, the data is stored in the database, and returned with a '1' prefix to signify the data was not returned from a cache. This allows the client app to prevent further HTTP requests until 1 second has passed. Note this page will work with any RESTful API, not just ESPN. If you build the app and have a less limited API key, I would highly recommend NOT using the proxy and removing the synchronization logic, as it really only slows the app down.
So that does it for data, onto the fun part - UI.
When starting this app, I decided to draw out some user interface before really knowing anything about android UI. I decided on a header bar that allows users to navigate around different sports, teams, leagues, etc, and a body with a sort of sliding-tab interface. When I started looking through the documentation, I found a similar control - SlidingDrawer. It had the functionality I wanted, but was limited to one drawer. So I figured 'no problem, I'll just make 4 sliding drawers'. Suffice it to say, the SDK designers did not have this in mind for this control, and it failed miserably. What is a programmer to do but build the control oneself? Probably my favorite component of this app is the MultiSlidingDrawer custom control. It allows virtually as many drawers as you want, and handles all the clicking, sliding, etc correctly for vertical. Haven't gotten around to fixing horizontal, should be close to working though. The 'Handles' and 'Contents' can be any view you want - I am using TextViews for the handles, and various viewgroups for the contents. I won't go over the code for the control, but it was a very interesting 'first task' to try and tackle. Suffice it to say a lot of the logic in the SlidingDrawer control took advantage of the fact that there could be only 1 drawer. I may polish it and load it up on GitHub as a stand-alone control, for anyone else that wants similar functionality (unless there is already something better available).
The header is used to control getting around the app, and can be seen in any of the screenshots. If you click on the baseball for example, you will be presented with http://i.imgur.com/sDgkb.png, and can select the sport you want to see. Each of the separators are custom drawn views (HeaderSeparator), with only a line and a filled triangle. Dummy text is placed in the 'next' space of a header, so if you are currently looking at Baseball->MLB, it will show '<select team>', if you want to find a team from the header.
Due to free tier API limitations, only 3 body contents are implemented: News, with real headlines, but dummy bodies, Teams under league, with dummy icons, and Roster under team, with dummy positions. The latter two have search boxes at the top (EditBox's hooked into a filterable custom BaseAdapter, ImgTextAdapter), and can be used to restrict the grid/list views by first name, last name, team, or position; essentially anything displayed for each item.
There are a number of features the app is lacking. Obviously, implementing schedule, scores, etc is important, as is fleshing out the search functionality so you can look for sub groups (AFC, NFC, etc). A splash screen at the beginning would be a nice way to let the background data threads work and load more data for immediate display. Probably the biggest point of silliness is the Spaghetti icon in lieu of real player headshots and team logos.
ESPN API Requests
The API was pretty easy to use and understand, and much of the functionality I wanted was available in higher tiers. Two outstanding requests though:
When I request all the leagues under a sport, teams under a league, etc, I would like to be able to request additional parameters, specifically API links. For my app, when the user clicks on 'MLB', I request all the teams in the MLB, and allow the user to choose one. Once one is chosen, I want to quickly display news and other data about that team, but I believe this requires two API calls - one to get the data about the selected team (including API URLs), and another to call the appropriate API to load the specific data. It would be nice if when returning all the Teams for MLB, it also returned specified API URLs (news, roster, standings in my case).
Some league abbreviations seem unexpected. For example, NCAA basketball, the abbreviation is 'mens-college-basketball', which is longer than the full name! Also, there is no difference in the full names for mens and womens college basketball - they both just say NCAA. In my app, I use abbreviation in the header control, so it is by necessity fairly short. To get around this, I hard-code mens-college-basketball to NCAA and womens-college-basketball to NCAA (W) (the user already knows it's basketball and not football by the icon in the top left). I would use the 'shortName' field instead, but it seems to not be present for most leagues, and 'name' is often too long.
K, that's it. Any feedback on the app, model, whatever would be greatly appreciated! As I said, it's simply a learning application, and if anyone looking at the code or UI sees obvious opportunities for improvement, it would only help me do a better job if I ever need to do something similar in the workplace.
Message edited by rollie 5 months ago
10 months ago
Hi everybody i need to list all the events under a league but m getting a following error :
<response><timestamp>2012-07-22T15:37:16Z</timestamp><message>This action is forbidden for the requested resource at your permission level. Please review the documentation for account level access.</message><status>error</status><code>403</code></response>
Can you please clarify this ?
5 months ago
I need to fetch tennis (Score & Schedules) data through ESPN API into our site, but I am getting a following error:
<message>This action is forbidden for the requested resource at your permission level. Please review the documentation for account level access.</message>
Please help me on this.
Please sign in to add a post.