Saturday 9 July 2011

ORMLite and Android a good Companion

Persistence with Android

When creating Android applications there are many ways for you to store data, each fit for its own purpose. Below is a quick break down of the 5 main and recommended ways for applications to persist data with Android. More information can be found on the developers guide
  • Shared Preferences - Ideal for application settings and small chucks of data which can be used globally within your application. Options include booleans, floats, ints, longs, and strings all which are stored as key-value pairs.
  • Internal Storage Ideal for storing application cache data, this medium is private to your application.
  • External Storage - Store public data on either removable storage media (such as an SD card) or an internal (non-removable) storage. Used for storing pictures, ring tones, music etc. 
  • SQLite Databases - Store structured data in a private database. The database is private to the application and consists of standard CRUD options.
  • Network Connection - Store data on the web with your own network server. Can be used for all purposes, will be familiarly to most Java developers, must have an available data connection for this to work. Classes with the following packages can be used, java.net.* or android.net.*
During the last 6 months I have been learning Android and slowly going though options available to me for each application or feature I create/add. I have experience using all methods for data persistence except External Storage which I have not come in to the situation where this would be the most appropriate method for the applications I have been creating. One point to emphasise is that when storing data for your application ensure you make the correct choice when choosing a persistence medium. I myself have chosen incorrect methods and tried to make it work for the wrong purpose, this will only end in dirty unmanageable code and an application which is hard to enhance at a later date.

As part of this guide I'm going to demonstrate how ORMLite can be used to aid and ease the development of Android applications and make storing data much easier than interfacing directly with Androids inbuilt SqlLite database.
About a month ago I stumbled across a object relationship mapping (ORM) library which supports Android. After a little investigation, porting an existing application and using it from scratch for a new application I am currently developing I deem ORMLite and Android to be a great companionship. As part of this post I will try and show you how easy it can be to use ORMLite for Android, plus demonstrating how I use the library and how it has naturally fit in with my current development practices and patterns.


Alternatives
There are afew alternatives available to using ORMLite two of which can be seen below. The other two projects are reasonably new and since the Android ORM space is still in early days I'm sure new libraries will emerge. I prefer the syntax when using ORMLite plus find it more intuitive to use and develop with. I also like the fact ORMLite is a multi functional library which supports several databases.

I am yet to do any performance based analysis on either ORMLite or any alternatives. At a later date I may re-create the example from this post in all three and try come up with some simple performance based analysis on the three ORM libraries mentioned.
Example Project
For the purpose of this example I will be creating a small Android Application which contains a one-to-many relational table structure which you will be able to view, add, edit and delete entries. All source files can be found at my Github account here.
The relationship consists of one PERSON has many APP's.
Setting up your project
1) Simply create a new Android project with the standard eclipse wizard. I've called mine DemoORMLite with the main activity called DemoORMLiteActivity.

2) Next download the packages ormlite-android-4.23.jar and ormlite-core-4.23.jar and add these to the classpath of your Android project. If your using Maven these packages appear to be accessible so add them to your pom as normal. You are now ready to use ORMLite.
Creating your domain classes
Below are the two domain classes I have created, Person.class and App.class. As ORMLite is annotation driven you simply annotate your classes with the required options, setting field constraints as required. Next annotate your class defining the table name. In this example I have followed the standard bean convention having private fields and public getter and setter methods, this is optional.

@DatabaseTable(tableName = "persons")
public class Person {

	@DatabaseField(generatedId = true)
	private int id;

	@DatabaseField(canBeNull = true)
	private String name;

	@ForeignCollectionField
	private ForeignCollection apps;

       // Getters and setters are also present but not show in this demo

	public Person() {
		// all persisted classes must define a no-arg constructor with at least package visibility
	}
}

@DatabaseTable(tableName = "apps")
public class App {

	@DatabaseField(generatedId = true)
	private int id;

	@DatabaseField(canBeNull = true)
	private String name;

	@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = "person_id")
	private Person person;

       // Getters and setters are also present but not show in this demo

	public App() {
		// all persisted classes must define a no-arg constructor with at least package visibility
	}
}

Creating your Database Helper
You will need to create a DatabaseHelper to allow ORMLite to create and manage your database. You can extend OrmLiteSqliteOpenHelper.class which will allow ORMLite to take over management. Simply create your table structure using helper methods such as the ones highlighted below. I also use this as an opportunity to expose my Dao's.

	// Should be called inside the onCreate method
	TableUtils.createTable(connectionSource, App.class);
	TableUtils.createTable(connectionSource, Person.class);

	// Should be called inside the onUpgrade method
	TableUtils.dropTable(connectionSource, App.class, true);
	TableUtils.dropTable(connectionSource, Person.class, true);

	// Exposing the Dao for App CRUD operations
	public Dao getAppDao() throws SQLException {
		if (this.appDao == null) {
			this.appDao = getDao(App.class);
		}
		return this.appDao;
	}

Creating your repository
The repository layer wraps all ORMLite calls hiding any exceptions and code relating to all database operations. This means when I use this in my Android Activities I will not have to deal with try/catch exceptions and can easily standardise what happens on these situations. Adding a further layer to your code may not always be suitable especially when using resource limited devices such as Mobile phones but I don't expect the impact to out way the code cleanliness/abstraction and ease of development when accessing a database via this means.


	// An example of a delete method on my repository
	public void deletePerson(final Person person) {
		try {
			final ForeignCollection apps = person.getApps();
			for (final App app : apps) {
				this.appDao.delete(app);
			}
			this.personDao.delete(person);
		}
		catch (final SQLException e) {
			e.printStackTrace();
		}
	}

Using with your Activity
Your activity will need to extend an ORMLite activity wrapper to enable your application to use the library (See below for a further explanation). Once you have extended the correct activity it can be treated exactly as the original parent class. Below is a sample of the DemoORMLiteActivity class onCreate method I created and how I use the repository mentioned before.

@Override
public void onCreate(final Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	// Create a new repo for use inside this activity
	this.demoRepository = new DemoRepository(getHelper());

	// Get all people, I use this to then create a simple list view and array adaptor.
	this.persons = this.demoRepository.getPersons();

	// Additional Android specific code in here
}

Why must I extend another Class?
Coming from a main enterprise Java background I'm used to simply using @Autowired or @Inject to obtain my Services and DAO's and letting my container deal with finding and setting the required fields etc. So the idea of extending a class just to be able to access my database layer is something I don't see too often but it isn't doing anything complicated and simply exposing ORMLite to the most common Android components. Check out the sourcecode for the four base classes (OrmLiteBaseActivityOrmLiteBaseListActivityOrmLiteBaseServiceOrmLiteBaseTabActivity) and you will find all set up and exposeure of a DAO layer which you can use inside your main Android Classes plus it will deal with opening and closing of your DB connections. I am yet to run into a scenario where the base classes don't fit my need, and if so you can always create you own.
Conclusion 
I have not gone in to great depth in this demo but simply tried to show how easy it can be to use ORMLIte with Android. Previously using Androids inbuilt DB classes has proven to me to time consuming, clunky and error prone, plus the code is never as clean as when using this library. All sources can be grabbed from my GitHub account here, the example application is a simple demonstration of some CRUD options inside a very simple Android application. In total the application took no more than 1hour to create. When using the application long press each row to get a list of options available to each entry and single click each row to get a list of applications each person has. 


All thoughts, comments and opinions are always welcome. 

James

No comments: