在Android中使用内容提供者公开多个表的最佳实践

我正在build立一个应用程序,我有一个活动桌和一个场地表。 我希望能够授予其他应用程序访问这些数据。 我有几个与这种问题的最佳实践有关的问题。

  1. 我应该如何构造数据库类? 我目前有EventsDbAdapter和VenuesDbAdapter类,它提供了查询每个表的逻辑,同时还有一个单独的DbManager(扩展SQLiteOpenHelper)用于pipe理数据库版本,创build/升级数据库以及访问数据库(getWriteable / ReadeableDatabase)。 这是推荐的解决scheme,或者我会更好的整合一个类(即DbManager)或分离的一切,让每个适配器扩展SQLiteOpenHelper?

  2. 我应该如何devise多个表的内容提供者? 扩展前面的问题,我应该为整个应用程序使用一个内容提供者,还是应该为事件和场所创build单独的提供者?

我发现的大多数例子只处理单个表格的应用程序,所以我会很感激这里的任何指针。

对你来说可能有点晚了,但其他人可能会觉得这很有用。

首先,您需要创build多个CONTENT_URI

public static final Uri CONTENT_URI1 = Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri1"); public static final Uri CONTENT_URI2 = Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri2"); 

然后你扩展你的URI匹配器

 private static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "sampleuri1", SAMPLE1); uriMatcher.addURI(PROVIDER_NAME, "sampleuri1/#", SAMPLE1_ID); uriMatcher.addURI(PROVIDER_NAME, "sampleuri2", SAMPLE2); uriMatcher.addURI(PROVIDER_NAME, "sampleuri2/#", SAMPLE2_ID); } 

然后创build你的表格

 private static final String DATABASE_NAME = "sample.db"; private static final String DATABASE_TABLE1 = "sample1"; private static final String DATABASE_TABLE2 = "sample2"; private static final int DATABASE_VERSION = 1; private static final String DATABASE_CREATE1 = "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE1 + " (" + _ID1 + " INTEGER PRIMARY KEY AUTOINCREMENT," + "data text, stuff text);"; private static final String DATABASE_CREATE2 = "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE2 + " (" + _ID2 + " INTEGER PRIMARY KEY AUTOINCREMENT," + "data text, stuff text);"; 

不要忘记将第二个DATABASE_CREATE添加到onCreate()

您将使用开关块来确定使用哪个表。 这是我的插入代码

 @Override public Uri insert(Uri uri, ContentValues values) { Uri _uri = null; switch (uriMatcher.match(uri)){ case SAMPLE1: long _ID1 = db.insert(DATABASE_TABLE1, "", values); //---if added successfully--- if (_ID1 > 0) { _uri = ContentUris.withAppendedId(CONTENT_URI1, _ID1); getContext().getContentResolver().notifyChange(_uri, null); } break; case SAMPLE2: long _ID2 = db.insert(DATABASE_TABLE2, "", values); //---if added successfully--- if (_ID2 > 0) { _uri = ContentUris.withAppendedId(CONTENT_URI2, _ID2); getContext().getContentResolver().notifyChange(_uri, null); } break; default: throw new SQLException("Failed to insert row into " + uri); } return _uri; } 

您将需要deleteupdategetType等。无论您的提供者要求DATABASE_TABLE或CONTENT_URI,您将添加一个案例,并在其中一个和第二个DATABASE_TABLE1或CONTENT_URI1,等等,尽可能多。

我build议查看Android 2.x ContactProvider的源代码。 (可以在网上find)。 他们通过提供专门的视图处理交叉表查询,然后在后端运行查询。 在前端,通过单个内容提供者可以通过各种不同的URI访问调用者。 你可能也想提供一个或两个持有你的表字段名称和URIstring的常量。 这些类可以作为一个API包含或作为一个类的下拉菜单提供,并将使消费应用程序更容易使用。

它有点复杂,所以你可能也想看看日历是如何得到你做什么和不需要的。

您应该只需要一个数据库适配器和每个数据库(不是每个表)的单个内容提供程序来完成大部分工作,但是如果您真的想要,则可以使用多个适配器/提供程序。 这只是让事情更复杂一点。

一个ContentProvider可以服务多个表,但是它们应该有些相关。 如果您打算同步您的提供商,这将会有所帮助。 如果您希望单独进行同步,比如联系人,邮件或日历,即使它们最终位于相同的数据库中,或者与同一服务同步,也需要不同的提供程序,因为同步适配器直接绑定到特定的提供者。

据我所知,每个数据库只能使用一个SQLiteOpenHelper,因为它将元信息存储在数据库中的一个表中。 所以如果你的ContentProviders访问同一个数据库,你将不得不分享一下Helper。

注意:这是对Opy提供的答案的澄清/修改。

这种方法使用switch语句分别insertdeleteupdategetType方法,以便处理每个单独的表。 您将使用CASE来标识要引用的每个表(或uri)。 然后每个CASE映射到你的表或URI的一个。 例如, TABLE1URI1在CASE#1中被选中,等等您的应用程序所使用的所有表格。

这是一个方法的例子。 这是插入方法。 它与Opy的实现有些不同,但执行相同的function。 你可以select你喜欢的风格。 我也想确保插入返回一个值,即使表插入失败。 在这种情况下,它返回-1

  @Override public Uri insert(Uri uri, ContentValues values) { int uriType = sURIMatcher.match(uri); SQLiteDatabase sqlDB; long id = 0; switch (uriType){ case TABLE1: sqlDB = Table1Database.getWritableDatabase(); id = sqlDB.insert(Table1.TABLE_NAME, null, values); getContext().getContentResolver().notifyChange(uri, null); return Uri.parse(BASE_PATH1 + "/" + id); case TABLE2: sqlDB = Table2Database.getWritableDatabase(); id = sqlDB.insert(Table2.TABLE_NAME, null, values); getContext().getContentResolver().notifyChange(uri, null); return Uri.parse(BASE_PATH2 + "/" + id); default: throw new SQLException("Failed to insert row into " + uri); return -1; } } // [END insert]