I want to implement a ContentProvider
that manipulates multiple tables. Here is what I tried so far. I wrote a Java Interface
that represents the CRUD operations that every table should implement in its CRUD class.
public interface CRUDHandler {
//UPDATE
int update(Uri uri, ContentValues values, String selection,String[] selectionArgs);
//READ
Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) ;
//CREATE
Uri insert(Uri uri, ContentValues values);
//DELETE
int delete(Uri uri, String selection, String[] selectionArgs);
//get Mime type
String getType(Uri uri);
}
Then I wrote an abstract
class
that defines a static UriMatcher
for the ContentProvider
so each class that extends
this class should add its Uri
that identifies it and provide an implementation for each method in interface.
The class looks like this:
public abstract class ApplicationCRUD implements CRUDHandler{
public static final UriMatcher sUriMatcher;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
}
}
Further, I created a class for each table that extends
this class and adds its Uri
's to the UriMatcher
from the abstract class.
Here is an example:
public class Table1CRUD extends ApplicationCRUD {
//Setup Projection Map for Table1
private static HashMap<String , String>sTable1ProjectionMap;
static {
sTable1ProjectionMap.put(ApplicationProviderMetaData.Table1MetaData._ID, ApplicationProviderMetaData.Table1MetaData.TABLE_NAME+"."+ApplicationProviderMetaData.Table1MetaData._ID);
sTable1ProjectionMap.put(ApplicationProviderMetaData.Table1MetaData.COL1, ApplicationProviderMetaData.Table1MetaData.TABLE_NAME+"."+ApplicationProviderMetaData.Table1MetaData.COL1);
sTable1ProjectionMap.put(ApplicationProviderMetaData.Table1MetaData.COL2, ApplicationProviderMetaData.Table1MetaData.TABLE_NAME+"."+ApplicationProviderMetaData.Table1MetaData.COL2);
}
public static final int INCOMING_SINGLE_URI_INDICATOR = 5;
public static final int INCOMING_COLLECTION_URI_INIDICATOR = 6;
static {
//standard URI
sUriMatcher.addURI(ApplicationProviderMetaData.AUTHORITY, "t1", INCOMING_COLLECTION_URI_INIDICATOR);
sUriMatcher.addURI(ApplicationProviderMetaData.AUTHORITY, "t1/#", INCOMING_SINGLE_URI_INDICATOR);
//here add your custom URI
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}
Now my ContentProvider
looks like this:
public class ApplicationProvider extends ContentProvider{
//Define TAG FOR EACH CLASS FOR DEBUGGING
private static final String TAG = "ApplicationProvider";
// Application CRUD Handlers use to support multiple tables inside the content provider
private static Table1CRUD table1CRUD;
private static Table2CRUD table2CRUD;
static {
table1CRUD = new Table1CRUD();
table2CRUD= new Table2CRUD();
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriMatchResult = ApplicationCRUD.sUriMatcher.match(uri);
//case Table1
if(uriMatchResult == Table1CRUD.INCOMING_COLLECTION_URI_INIDICATOR ||uriMatchResult == Table1CRUD.INCOMING_SINGLE_URI_INDICATOR )
{
return table1CRUD.delete(uri, selection, selectionArgs);
}
case Table2
else if(uriMatchResult == Table2.INCOMING_COLLECTION_URI_INDICATOR|| uriMatchResult ==Table2.INCOMING_SINGLE_URI_INDICATOR){
return table2CRUD.delete(uri, selection, selectionArgs);
}
else{
throw new IllegalArgumentException("Unknown Uri "+uri);
}
}
Now I am using the SQLiteOpenHelper
as a private class in the ContentProvider
and I define an instance of it in my ContentProvider
. Should I modify the interface and supply each CRUD method that object Dependency Injection
to let each function use it to access the database? I also want to know what you think about this approach: Is it good enough? Does it make the thing I am trying to do efficiently? What modification can I do to improve this design?
SQLite JOINS are used to retrieve data from multiple tables. A SQLite JOIN is performed whenever two or more tables are joined in a SQL statement.
A content provider manages access to a central repository of data. A provider is part of an Android application, which often provides its own UI for working with the data. However, content providers are primarily intended to be used by other applications, which access the provider using a provider client object.
To access the data from a content provider, URI is used as a query string. Details of different parts of Content URI: content:// – Mandatory part of the URI as it represents that the given URI is a Content URI. authority – Signifies the name of the content provider like contacts, browser, etc.
Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications.
The Google IO Schedule application is a good resource if you are need to design a ContentProvider
with multiple tables. It sounds like you want to do something a bit more complicated, but maybe it will help.
I have gone through the opensource project, in which they have used multiple tables. You can look at the various projects of OpenIntents and here is a similar question.
I hope, it can help you .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With