问题
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?
回答1:
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.
回答2:
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 .
回答3:
Why don't you make multiple tables under a content provider this way.
Suppose you have two tables named A and B, their URI's would be AUTHORITY/A, AUTHORITY/B
private static final int TableOne = 1;
private static final int TableTwo = 2;
private static final UriMatcher uriMatcher;
static{
uriMatcher.addUri(AUTHORITY,"A",TableOne);
uriMatcher.addUri(AUTHORITY,"B",TableTwo);
}
Now you can implement the overridden methods using a standard switch case , and mapping correctly to the underlying SQLite Database class's methods.
来源:https://stackoverflow.com/questions/9881758/contentprovider-with-multiple-tables