I’ve been looking for the best architecture for an Android app. I’m not looking for the best speed or performance, but they should be acceptable. It should be quite Android-compliant and above everything, easy to replicate. My final target is to have a foundation for new projects (pro and personal ones) and be able to say “this is the way I work”. I have a lot of ideas in my mind, but without sharing or discussing them, they are worthless. So, let’s share them, discuss them and let´s improve together.

I’ll start talking about Content Providers (CP). I’m assuming that you know what they are and how they work, and also about SQLite and all the related stuff. If you don’t know about these topics, check out the tutorial from our friend Vogella at  http://www.vogella.com/articles/AndroidSQLite/article.html.

Check section 9.4 of that tutorial. You’ll see the structure of a CP. Basically, four functions, one per operation (query, insert, delete and update) with an structure like this:

I hate the switch statement. I think is ugly and unmaintainable. Also, the example is using only two URLs, but an app with 20 entities will easily become a God class.

My proposal is an structure I call the DespicableContentProvider. Why? because it has MinionContentProviders (I know, don’t use cute names, but I couldn’t resist and the analogy helps a lot to understand it). If you don’t know anything about Despicable and Minions, chech this: http://www.youtube.com/watch?v=jzpOLs1t8Hg

You can check the code both for the Despicable base class and the Minion base class at https://gist.github.com/sergiandreplace/8165986. Free, cute and distributables.

Before start working with them, let’s see some rules I follow when working with CP:

  • The CP works like a web api. Authority is the host name.
  • Every url is an endpoint for an entity.
  • Urls are like content://<authority>/<entity>[/#id].
  • Urls ending with an id are asking for an specific element and are type Item. Other ones are Dir type (for coherence with MIME types)
  • Mime type will be vnd.android.cursor.{dir|item}/vnd.{AUTHORITY}.{ENTITY}. My CP are usually private for the app, so I don’t care too much about MIME types.
  • CP consumers know NOTHING about the database. In fact,  the only one accessing the database is the CP. Even for big projects I use different contracts. One for the database and another one for the CP consumers.
  • When performing an Item request (one with an id in the url) all the filtering parameters are ignored (I’m already asking for only one, why filter?)

Basically, every Minion knows how to perform an Insert, Update, Delete or Query against an entity for an Item or a Dir (not both). Here is an example:

Basically I’ve implemented three things, first getBasePath, that returns the specific url path to the entity, getType function, that returns the name to be used to indentify this entity as MIME type, and the four operations for this specific entity. The main difference with the CRUD opeartions are that you receive the db object via parameter and you don’t need to notify the change as the Despicable will do it.

An Item type is very similar:

The main differences are:

  1. Class name is singular (it’s my way…)
  2. Return path now includes /# as per UriMatcher syntax
  3. On each one of the CRUD operations we ignore the parameters received for filtering and we just query by _id
  4. In this case, I’ve decided you can’t insert an Item specifying an id in the path. This is just an example, and real behaviour will be domain-specific.

Easy peasy, isn’t? So we only need to create one per entity.

Once we have the Minions, let’s work on the Despicable. Check this:

GetAuthority method just returns the name of the authority. It’s used by the parent class to retrieve it on runtime. The method getDb should return a database to work with. The recruitMinions method is responsible to add an instance of each Minion to the collection of the Despicable.

That’s it. Quite cool, isn’t it. At least is tidier and easier to maintain.

Now, our CP implements the  four operations for each entity, and also a bulk insert that just executes the insert in a loop inside a transaction.

And for the same price, a couple of helping functions I usually include in the CP.:

They are very useful in the contract and the CursorHelpers that will be discussed in next entry.

I’d love to receive comments about this and see other points of view and ways of working with CP. And also, any suggestion or improvement will be very welcome.

 

3 Responses to Looking for the perfect Android architecture I: Despicable Content Providers

  1. DCam says:

    I like the despicable/minion metaphor.

    I’m looking at adding several content providers to an app I’m working on, and this looks like a nice pattern. My app has different permissions for different ContentProviders, so that would require more than one DespicableContentProvider, since they are the “true” ContentProviders, in the Android sense.

    We were kicking around the idea of a ContentProvider framework inspired by MVC web frameworks, and I think you’ve started something like that.

    • sergi says:

      Hi

      Yes, the Despicable is the true CP, the minions are just modules handling different urls in the same CP.

      I’ve never did it, but theoretically you must be perfectly able to have more than one Despicable at same time. Just tell me if you try it.

      I strongly disagree with the MVC approach to Android, as I believe the platform is not MVC. Of course some parts can be taken from there (specially the M part with CPs), but the separation between Views and Controllers is not so clear to me.

      My next article is about the general architecture I use in my apps. It’s in Spanish an under translation. Give me a little time and you’ll be able to read it.

      • DCam says:

        Oh, I was thinking MVC specifically for the ContentProviders, drawing an analogy to a Rails or Sinatra app that is serving a Restful API. In a conversation with a work colleague, I just described your DespicableContentProvider as “a bit like a router” and the MinionContentProviders as “a bit like controllers.”

        Not sure if that clarifies. In terms of the overall Activity, ContentProvider, Service component families mapping to MVC — I agree with you, they do not map.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">