views:

265

answers:

2

I have created a ContentProvider for my main Sqlite table, pretty much following NotePad example from SDK (although I am not sure whether I will ever be exposing my data to other apps). However, I need to create lots of other, non-trivial queries on that and other tables and views. A good example would be queries to extract some statistics from the base data, averages, totals etc.

So what's the best place for this code in an Android project? How it should be related and connected to the Uri-based data access exposed by a Provider? Any good examples out there?

+1  A: 

If your data is just being accessed by your app then I would suggest skipping the content provider altogether. The reason being, it will add unnecessary layers between your app and the DB which won't help performance.

I recommend writing a class whose only job is to update/query the database. Then from your other classes/activities you can instantiate this DB access class to get data or put data.

You can have multiple instances of your DB class running at once.

Edit: Sample code snippets (I took the class definition and a couple methods from my working code) It was my first app, so its not perfect, but it works:

public class VoyagerDB extends SQLiteOpenHelper {
    @Override
    public void onCreate(SQLiteDatabase db) {
            boolean ret = false;

            // build out the schema
            ret = populateSchema(db);

    }


    /**
     * Returns information from a given obdRequest record.
     * @param requestID
     * @return
     */
    public Cursor getRequestInfo (String requestID) {

            Cursor c = null;

            String sql = "SELECT id _id, active,request,formula, description,frequency,minValue,maxValue,numDataBytes " +
                            "FROM obdRequest " +
                            "WHERE ID=" + requestID;

            c = localDBRW.rawQuery(sql, null);

            return c;
    }


    /**
     * If the given settings key exists in the DB, return its record ID. Otherwise return blank.
     * @param key
     * @return
     */
    public String settingsKeyExists (String key) {
            String recordID = "";
            Cursor c = null;

            String sql = "SELECT id,key,value from settings WHERE key = ?";
            String selectionArgs[] = {key};
            c = localDBRW.rawQuery(sql, selectionArgs);

            if (c == null) {
                    return "";
            }
            if (c.getCount()<1) {
                    c.close();
                    return "";
            }

            c.moveToFirst();
            recordID = c.getString(c.getColumnIndex("id"));
            c.close();

            return recordID;
    }

}
Brad Hein
Is there any particular class or interface that this DA class of mine should inherit/implement? Should it somehow be related with `SQLiteOpenHelper`? How should it receive/keep/resolve `SQLiteDatabase` instance? Any good example I can take a look at?
Mladen Jablanović
I added a few chunks of sample code to my answer that should get you on the right track. For more details consult the SDK Documentation.
Brad Hein
Thanks. Can you just write how and when do you initialize attribute `localDBRW`?
Mladen Jablanović
localDBRW is a `getWritableDatabase()`. It is defined as a reference to `getWritableDatabase()`. Instead of localDBRW I recommend just calling getWritableDatabase() when you need it. For example `getWritableDatabase().rawQuery(.......`
Brad Hein
@Brad can you take a look at this: http://stackoverflow.com/questions/3147910/c-property-syntax-in-java
Jere.Jones
+2  A: 

From the point of view of maintainabillty I think that the provider model is the cleanest way to abstract the data access code. And from experience having worked on a large application, eventually the application will grow to the point where some data must be exposed via the provider model (e.g. introducing services to the application). That said exposing many different views of your data can be a lot of work in the provider model.

If you were to go the route I would think carefully how you exposed the data through URLs, and usually some of the complexity you talk of can be managed with use of sub-directories representing different views of the data (similar to a REST approach).

If you wish to avoid the provider model, then implementing a DA class is fairly straight forward. Typically a SQLiteOpenHelper is creatd as an inner class to the DA class (the open helper also providers basic versioning support) and an instance of this class is used to create database connections in the DA functions. There are many examples in the Android Source code. Look at any of the provider implementations, with MediaProvider.java probably being the most relevant as it uses quite complex searches for a provider. For example from the source code that is not a content provider see DbSSLSessionCache.java

Nic Strong
Thanks, just the kind of answer I was looking for. I guess I can always build provider _on top_ of existing DA, as it _is_ a kind of additional layer. Personally, I see two main reasons to choose DA over Provider: provider model requires considerably more boilerplate code, and it requires more planning ahead, well-thought URIs etc. I may be wrong though, I'm kinda biased - working mostly in Ruby. :)
Mladen Jablanović
Yeah I would agree with what your conclusions. But some structures of data fit very nicely into the provider model (e.g. hierachial data)
Nic Strong