Thursday, August 29, 2013

Quick Notes on Android RSS

This is a quick and dirty post for a very small user base, but I figured it's been a while so I thought I'd throw up something new.

I am building a podcast app in android, and I'm using Android Annotations (AA) for the feed reading. AA uses Spring Android for the rest (de)serialization, which uses the Android ROME Feed Reader for the various rss formats, which is what I need for my podcasts. Everyone follow that chain of dependencies? Good. Don't forget JDom at the end or ROME blows up. ;-)

So AA allows me to set the converter for reading the xml like so:
@Rest(rootUrl = "", converters = { SyndFeedHttpMessageConverter.class,  })
The problem here is SyndFeedHttpMessageConverter only supports application/atom+xml and application/rss+xml out of the box. And anyone who's ever tried to consume web code knows that everyone and their mother has a content type to use because the format is pretty open. So you wind up with rss or atom sites with contentTypes of application/xml or text/xml, which will fail.

AA doesn't let you set the accepted media types, however, at least not as of version 2.7.1 - so you are forced to leave them behind, which is what I did here. All you have to do is copy out the AA generated code and make your changes, but it's not easy to figure out that that's an actual shortcoming of AA, hence this post. Here's my new shiny code, with the changes in bold:
public class PodcastReaderProxy2
{
    private RestTemplate restTemplate;
    private String rootUrl;
    public PodcastReaderProxy2() {
        restTemplate = new RestTemplate();
        SyndFeedHttpMessageConverter converter = new SyndFeedHttpMessageConverter();
        List<MediaType> supportedTypes = new ArrayList<MediaType>();
supportedTypes.addAll(converter.getSupportedMediaTypes());
supportedTypes.add(MediaType.APPLICATION_XML);
supportedTypes.add(MediaType.TEXT_XML);
converter.setSupportedMediaTypes(supportedTypes);
restTemplate.getMessageConverters().add(converter);
        rootUrl = "";
    } 
    public void setRootUrl(String rootUrl) {
        this.rootUrl = rootUrl;
    } 
    public SyndFeed getFeed() {
        HttpHeaders httpHeaders = new HttpHeaders();
        HttpEntity<Object> requestEntity = new HttpEntity<Object>(httpHeaders);
        return restTemplate.exchange(rootUrl.concat(""), HttpMethod.GET, requestEntity, SyndFeed.class).getBody();
    }
}
 Hopefully this post saves someone else doing REST with AA some time: while my example is focused on podcasts, it's definitely helpful to anyone looking to add some additional supported media types to their web calls.

Some Links:
https://github.com/excilys/androidannotations/wiki/Rest-API#rest
http://www.springsource.org/spring-android
http://static.springsource.org/spring-android/docs/1.0.x/reference/htmlsingle/

Happy Coding!

Thursday, April 11, 2013

Extending Dobjanschi - An Attempt at an Android REST Client Pattern


I've been working on several mobile apps, most of them needing some way to communicate with services of the REST variety. This is an incredibly useful talk from Google I/O 2010 by Virgil Dobjanschi - if you make RESTful clients and haven't seen it, I recommend you find an hour to watch it and then find considerably longer to digest it.

Google I/O 2010 video and presentation materials here.

The pattern that really jumped at me was B: the idea of sending everything through the Content Provider. So I started making a 'simple' POC that quickly grew out of control. Without going into the development details TOO much at this point, I was stuck on two points:

  • I didn't like the idea that my CRUD calls to the Content Provider were either hitting a service, or hitting a local database. I wanted to distinguish them.
  • When Dobjanschi made his talk, Loaders didn't exist yet.

In the end, I created a pattern that was something of an amalgam of A and B: I've attempted to draw it here.

To explain in words:

  • Your activity/fragment inits a Cursor Loader and assigns something (probably itself) as a callback.
  • Your activity/fragment creates an adapter - probably ideally something that extends CursorAdapter - and assigns it to your listviews, etc.
  • Any time your activity/fragment needs to DO something (even w/o user interaction, like making a refresh request on load) it calls into your Content Manager.
  • Content Manager crafts your intent and fires it off to your Service Helper.
  • Service Helper, a singleton, tracks existing calls. If your call is a 'new' one not already running, it fires it off to the Service - which uses Intent Filters.
  • The Service (which maybe or maybe not has a queue of requests and processes them one at a time) makes your REST params, spins up a new thread, and passes them to the REST Method.
  • The REST Method handles the HTTP request/response calls, and sends the raw data to the Processor.
  • The Processor munges response data into some Content Provider-centric logic (either DTOs, or if you prefer straight to ContentValues) and makes the CRUD calls into the CP to make your database reflect the results.
  • After finishing, the Processor notifies the Content Resolver of new data. This can also be done pre- or post- HTTP request/response, if you want to show the loading process to the user. (In which case, the REST Method will need to call the Processor during each step.)
  • Because you already registered your UI components, the rest is 'magic': your adapter will find the new data and refresh the UI automatically.
This assumes a SQLite database behind your Content Provider - I put another layer between my CP and my DB and called it "__DataSource" - my CP handles the URI routing to different DataSource methods while DataSource handles the actual heavy lifting (making queries, parsing ContentValues, etc). I've also found it handy for my DTOs to have 'fromCursor' methods on them - makes it very easy for my adapter to do something like "view.bind(Data.fromCursor(cursor));" in bindView.

Hopefully this gives some good direction on how I've gone about implementing a responsive client. I feel the pattern is good enough that it works beyond REST - any long-running async calls would likewise benefit from something like this, and it keeps you from having to constantly know WHEN to update the front end. You just bind it, and walk away: whenever the data changes, you sound off to the Content Resolver and any active pieces that care come running.

Up next (soon I hope) I'll discuss using an in-memory-only "database" for your Content Provider repo.

Happy coding!