Saturday, December 19, 2009

Structuring An Android Application For Reuse

The Android application I'm working on consists mostly of code that's not Android-specific:

- Database schema creation.
- SQL queries.
- Data access (objects mapped to and from database).
- Business logic.

There is only a small amount (less than 10%) of Android-specific GUI and notification code.

Other than the code that creates the database schema (which is database-specific), all of the non-Android code is device- and OS-agnostic. It just needs a Java runtime.

I wanted to be able to easily reuse the portable code to run the application on a website, and on other Java-based handhelds.

The first step involved abstracting the database so that any database can be used, instead of just Android's binding to SQLite:

http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortable/src/main/java/com/jimandlisa/common/database

and also abstracting the logger:

http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortable/src/main/java/com/jimandlisa/common/logging

Once that was done, I could test the database and logger independently from Android:

http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortableTestUtils/src/main/java/com/jimandlisa/common/testutils

http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonDatabaseTestUtils/src/main/java/com/jimandlisa/common/testutils/database

http://code.google.com/p/blog-code-hosting/source/browse/#svn/trunk/android/reuse/CommonPortableTests/src/test/java/com/jimandlisa/common/tests

The portable business logic is in another set of projects:

MyAppPortable
com.jimandlisa.myapp.common
com.jimandlisa.myapp.controller
com.jimandlisa.myapp.database
com.jimandlisa.myapp.model

MyAppPortableTestUtils
com.jimandlisa.myapp.testutils

MyAppPortableTests
com.jimandlisa.myapp.tests


Finally, the Android-specific code is in two more projects:

MyAppAndroid
com.jimandlisa.myapp

MyAppAndroidTests
com.jimandlisa.myapp.android.tests


The inter-project dependencies look like this:

CommonPortable:
n/a

CommonPortableTestUtils:
CommonPortable

CommonPortableDatabaseTestUtils:
CommonPortable
CommonPortableTestUtils

CommonPortableTests:
CommonPortable
CommonPortableTestUtils
CommonPortableDatabaseTestUtils

MyAppPortable:
CommonPortable

MyAppPortableTestUtils:
CommonPortable
MyAppPortable

MyAppPortableTests:
CommonPortable
CommonPortableTestUtils
CommonDatabaseTestUtils
MyAppPortable
MyAppPortableTestUtils

MyAppAndroid:
CommonPortable
MyAppPortable

MyAppAndroidTests:
CommonPortable/target/classes
MyAppPortable/target/classes
MyAppAndroid/bin
CommonPortableTestUtils
MyAppPortableTestUtils


The CommonDatabaseTestUtils are broken out from CommonPortableTestUtils because they depend on JARs that aren't loaded on the device, so they can't be included in the dependencies for MyAppAndroidTests.

MyAppAndroidTests depends on target/classes and bin for reasons explained in http://jimshowalter.blogspot.com/2009/10/developing-android-with-multiple.html.

So was it worth it?

Well, yes, and no.

There are definitely advantages:
  • I can write any other database-intensive application by cloning this setup and reusing the code in com.intuit.jimandlisa.common.*.
  • The database-abstraction layer doesn't have the problems reported in Google Android issues #3302, 3296, and 3304.
  • Having much of the code be regular, portable Java makes it easier to write coverage tests because EasyMock, JMockit, and Cobertura are available.
But there are also disadvantages:
  • This approach creates a lot of separate projects, and that's kind of a pain to set up.
  • I have to maintain the database-abstraction layer.
  • More work is required to mature the database-abstraction layer. (It currently doesn't support binding args or compound keys, all keys must be longs, etc.)
  • Because the database-abstraction layer isn't a native binding, it's slower. For a cellphone app with a few database operations per hour, this doesn't matter, but it will matter on a website.
On balance, the approach makes sense for the particular application I'm working on, because it is almost entirely not tied to Android. But the approach wouldn't be appropriate for a GUI-intensive application that makes a lot of calls to Android APIs.

It might be better to model the application, and generate the code. With so many devices, OSs, and vendors, code generation might be the only pragmatic way to develop a cross-platform application.

Update: The sample code has been updated to add createSchema and updateSchema to AbstractDatabase in order to make execSql private.

5 comments:

  1. Would you be interested in working on a code generator to generate orm code for Android, Webapp and possibly other frameworks from a single definition file?

    Let me know if you are interested: eukreign@gmail.com

    ReplyDelete
  2. This is one of the knowledgeable post.I like your blog features.This is one of the specific post.
    Android app developers

    ReplyDelete
  3. Rize provide onsite, near shore and dedicated offshore web design, development, testing, SEO and tech support teams to work for our clients through our primary operation and offshore development centers in US, Canada and India.

    ReplyDelete
  4. ery useful information for Andriod development …Thank you for sharing this information… Buzz Application

    ReplyDelete
  5. well post Vendorzapp provides Mobile apps for small business, Ecommerce android apps India, iOS ecommerce apps, Ecommerce website Pune, Ready ecommerce website and apps. Android ecommerce apps then visit now Ecommerce android apps India, iOS ecommerce apps, ecommerce website for small business call us +91-9850889625

    ReplyDelete