【问题标题】:ContentProvider with multiple tables具有多个表的 ContentProvider
【发布时间】:2012-04-10 12:36:14
【问题描述】:

我想实现一个操作多个表的ContentProvider。这是我到目前为止所尝试的。我写了一个 Java Interface 代表每个表应该在其 CRUD 类中实现的 CRUD 操作。

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);
}

然后我写了一个abstractclass,它为ContentProvider定义了一个静态UriMatcher,所以extends这个类的每个类都应该添加它的Uri来标识它并为每个方法提供一个实现在界面中。

类如下所示:

public abstract class  ApplicationCRUD  implements CRUDHandler{

    public static final UriMatcher sUriMatcher;

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    }
}

此外,我为extends 这个类的每个表创建了一个类,并将其Uri 添加到抽象类的UriMatcher 中。

这是一个例子:

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;
    }

}

现在我的ContentProvider 看起来像这样:

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);
        }
    }

现在我使用SQLiteOpenHelper 作为ContentProvider 中的私有类 我在ContentProvider 中定义了它的一个实例。我是否应该修改接口并提供对象Dependency Injection 的每个CRUD 方法以让每个函数使用它来访问数据库?我也想知道你对这种方法的看法:它足够好吗?它是否使我想要有效地做的事情?我可以做哪些修改来改进这个设计?

【问题讨论】:

  • 不要向此处仅提供链接的 cmets 向无关的问题发送垃圾邮件。有你在 StackOverflow 上的经验的人应该更了解。

标签: java android design-patterns android-contentprovider


【解决方案1】:

如果您需要设计具有多个表的ContentProviderGoogle IO Schedule 应用程序是一个很好的资源。听起来您想做一些更复杂的事情,但也许会有所帮助。

【讨论】:

  • 很抱歉打扰您,但我一直在尝试找到任何有关当您拥有主数据表时如何处理 CRUD 操作的示例,例如作者书籍、订单详细信息,但不幸的是我一直找不到任何东西。 ContentProvider 的insert 方法就是一个例子,它只需要两个参数:Uri 和ContentValues。我不知道在这种情况下该怎么做,因为我显然需要传递两个 URIs 并且可能比单个 ContenteValues 对象更复杂。您知道我可以使用哪些资源作为指导吗?
【解决方案2】:

我浏览了开源项目,他们在其中使用了多个表。您可以查看OpenIntents 的各种项目,这里是similar question
希望对你有帮助。

【讨论】:

    【解决方案3】:

    你为什么不以这种方式在内容提供者下创建多个表。

    假设您有两个名为 A 和 B 的表,它们的 URI 将是 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);
         }
    

    现在您可以使用标准 switch case 实现被覆盖的方法,并正确映射到底层 SQLite 数据库类的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      相关资源
      最近更新 更多