Android persistance
Cursor Representation Object Mapping
Crom is a simple library supports work with Cursors and ContentValues. Basicaly CROM transforms Cursor to POJO or POJO to ContentValue. Crom also includes CromLoader (oh yea, cool right? :) ) so you can obtain data automaticaly in backgroud.
Look at github repo: github.com/rysiekblah/crom
Inspiration
I was working on mobile app, and one requirement was that app should keep user's data.
Caching data is nothing unusual. For example creating YATA (Yet Another Twitter App) also would need this feature.
BTW, YATAPP is very frequent choice made by new Android devs :)
OK, let's take a look what Android offers in terms of Database.
Android DB
Android has database by default - sqlite. This is simple relation DB.
SQLite is an embedded SQL database engine. Unlike most other SQL databases, SQLite does not have a separate server process. SQLite reads and writes directly to ordinary disk files. A complete SQL database with multiple tables, indices, triggers, and views, is contained in a single disk file.If you are courius about sqlite, look here: www.sqlite.org/about.html
Access to DB on Android - 3 ways
SQLiteDatabase - Exposes methods to manage a SQLite database.
ORMLite – very nice ORM lib works on Android, uses SQLiteDatabase
ContentProvider – it is like adapter for SQLiteDatabase and CP can by public for many apps (on the same device:))
SQLiteDatabase
Exposes methods to manage a SQLite database. SQLiteDatabase has methods to create, delete, execute SQL commands (CRUD), and perform other common database management tasks.
All good so far I hope, so look at SQLiteDatabase API. For example query method:
query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)So, API doeasn't look comfortable to use :) That's why I prefer ContentProvider.
There is also problem with concurrency. You have to make sure, you have only one instance it SQLiteDatabase instance. To avoid concurrency problems, only one instance is recommended. And, filks, as I mentioned, Coursor is like JDBC RowSet. Query methods returns Cursor – not nice format – it is like jdbc's RowSet (getInt(), getString() ...)
ContentProvider
Content providers are one of the primary building blocks of Android applications, providing content to applications.
But I don't really aggree that a content provider is only required if you need to share data between multiple applications.
ContentProvider is perfect class in terms of DB access:
- It uses SQLiteDatabase, but it is safe.
- Access from application context
- It is separated part of your app, like adapter.
- Can be public for other apps, eg. Contact list
- It also returns Cursor
Okey, great! So we have everything. But how to deal with Cursor? Ha! What is a Cursor?!?!?
If you have experience with JDBC, RowSet is equvalent for Android's Cursor.
Cursor is interface which provides random read-write access to the result set returned by a database query.
You can iterate over Cursor and take appropriate field of certain type like String, Integer etc.
Simple? .. Well not really. Look at helper class below.
Helper class to conver Cursor to object.
public class Person { private String name; private int age; … public static Person fromCours(Coursor c) { String dname = c.getString(c.getColumnIndex(“name”)); … return new Person(dname, dage); } }
Do you like this code? Yes this is nothis special and for sure this is not racket science. I would say more, this is boilareplate! So I don't like it!
CROM
CROM is open source library. Why open source? Well, I have this comfort that more then one product can use it, more users more tests, more chance for fixes of bugs etc and this is all for free. That why :)
Good question is what library might me created. Painful coding is a trigger (CROM had this trigger), and when you notice that you can commonize your solution.
Let's assume we want to keep in DB Emploee data, so we need class for this:
public class Employee { @Column private String name; @Column(name="salaries") private Integer salary; public Employee() { } public Employee(String name, Integer salary) { this.name = name; this.salary = salary; } public String getName() { return name; } public Integer getSalary() { return salary; } }
You probably noticed @Column
annotation. CROM library will use annotated fields during conversion from Cursor.
Now is good time to create Crom object. But guys, good question is where create this object! If you are experienced Androdev
you know that we have something like Application, and this is the best place for this. Why? Because CROM has internal cache! :-)
So it might look like this: Crom crom = new Crom();
And now, somewhere in your code, you have got Cursor, and conversion to our Employee object looks like this:
Employee employee = crom.cursorToPojo(cursor, Employee.class);
Summary
We have talked about Android Ddatabase and how to store and obtain data in/from sqlite. We have looked at CROM libray which might help you with this kind of cases, I mean when you have to use DB.
Stay tuned, soon article about schema, what is also interesting topic, and might be painful sometimes if you are not careful :)
CROM code: github.com/rysiekblah/crom