10

I'm currently developing an android app that interacts with a RESTful webservice. The client is able to perform full CRUD on the webservice. After searching for best practices I watched the Google I/O 2010 keynote about REST clients which is cited in almost all articles.

To use as much of the android platform as possible, I decided to go with Option B using a ContentProvider and a SyncAdapter. This provided me with the built-in account system, content observers and periodic syncs when internet is availble.

Because one very important feature of our App is offline editing and availability (it is used in environments with bad reception) we want to keep as much relevant data locally as possible.

The client communicates with the server using a RESTful API in Json, the data from the server is deserialized using Gson on Models (POJO's, Plain old java objects).

To keep the code clear and easy to read I tried building my own object mapper instead of using a Cursor directly. This mapper provides default CRUD-operations and maps Cursors to Models when reading data and Models to ContentValues when writing data.

However, this architecture feels very bloated.

  • First of all it is not possible to get reliable information about the current SyncState (to provide feedback to the user). (Now "hacked" using this SO answer)

  • The second problem is that for each resource I will need: A model, A mapper, A table definition and ContentProvider URIs. Which is a lot of code to manage for just one resource.

  • The third problem is that requiring Models through my mapper I blocked myself from using a CursorLoader in the Activities.

Bottom line

I'm looking for a maintainable and lightweight way of having offline content and synchronisation with a RESTful webservice using Json. Also I would like to be able to use Models in my code because user.getName() is a lot more developer friendly than cursor.getString(cursor.getColumnIndex(UserDataSource.COLUMN_NAME)); (Which is currently hidden in my Mapper class).

A good example on mapping would be Dapper combined with Dapper Extensions written for .NET but similar to my approach, however my approach required all columns and fields to be defined in many different files (see above).

Also, I'm considering to drop the ContentProvider from my code because it feels very bloated and obsolete for such a simple task.

Community
  • 1
  • 1
christiaanderidder
  • 655
  • 1
  • 8
  • 18
  • IMHO, ContentProvider + Cursors are better for ListView than POJO ... with POJO you'll have many problems with data refreshing(how POJO or POJO's Array/ListArray will know if data change on server and you synchronize it) ... about problems: 1st doesn't matter every single use of update/insert/delete of CP will try to synchronize to server ... 2nd so do not write it by yourself ... made some code generator(fx.: from XML or compiletime Annotations) or use Annotations for runtime generating CP ... 3rd true ... thats why i'm not using it at all ... – Selvin Mar 21 '13 at 15:49
  • Are there any good existing solutions for #2 or maybe even something more complete, for example a wrapping library that just requires one defenition per resource? And I agree about #1 and #3 but we use some custom ways of displaying data (canvas). I guess this would be solvable by implementing some sort of cursor adapter. Although i'm not sure if this is possible with canvas. – christiaanderidder Mar 21 '13 at 17:08

1 Answers1

1

Have you considered using an ORM? I've had success with a combination of OrmLite and Jackson in the past. You will have to write your own service for synchronization, but OrmLite takes care of the heavy lifting when it comes to your data models.

Although you won't get some of the niceties that the ContentProvider + SyncAdapter combination provides (still no CursorLoader when you're using POJOs), this setup may ease the burden of a complex schema and/or lots of types.

Here's an example of a table definition from OrmLite's homepage:

@DatabaseTable(tableName = "accounts")
public class Account {
    @DatabaseField(id = true)
    private String name;

    @DatabaseField(canBeNull = false)
    private String password;   
}

As you can see, the model + mapping + table definition comes together very quickly and painlessly.

klmprt
  • 651
  • 6
  • 7
  • I did consider using an ORM, but I am still wondering about best practice on android because ContentProvider+SyncAdapter does provide some extras, but on the other hand require a lot of bloat.I will accept your answer because I will probably try the ORM method for the sake of readability and maintainability. – christiaanderidder Mar 23 '13 at 08:50