programacion - Mejores prácticas para exponer tablas múltiples usando proveedores de contenido en Android
proveedor de contenido definicion (4)
Es probable que sea un poco tarde para ti, pero a otros les puede resultar útil.
Primero debes crear múltiples CONTENT_URIs
public static final Uri CONTENT_URI1 =
Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri1");
public static final Uri CONTENT_URI2 =
Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri2");
Luego expandes tu URI Matcher
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);
}
Luego crea tus tablas
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);";
No olvides agregar el segundo DATABASE_CREATE
para onCreate()
Vas a usar un bloque de caja de interruptor para determinar qué tabla se usa. Este es mi código de inserción
@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;
}
Tendrá que especificar la delete
, update
, getType
, etc. Dondequiera que su proveedor llame a DATABASE_TABLE o CONTENT_URI, agregará un caso y tendrá DATABASE_TABLE1 o CONTENT_URI1 en uno y el # 2 en el siguiente, y así sucesivamente, para todos los que desee .
Estoy construyendo una aplicación donde tengo una mesa para eventos y una mesa para lugares. Deseo poder otorgar acceso a otras aplicaciones a estos datos. Tengo algunas preguntas relacionadas con las mejores prácticas para este tipo de problema.
¿Cómo debería estructurar las clases de la base de datos? Actualmente tengo clases para EventsDbAdapter y VenuesDbAdapter, que brindan la lógica para consultar cada tabla, mientras tengo un DbManager separado (amplía SQLiteOpenHelper) para administrar versiones de bases de datos, crear / actualizar bases de datos, dar acceso a la base de datos (getWriteable / ReadeableDatabase). ¿Es esta la solución recomendada, o sería mejor consolidar todo en una clase (es decir, el DbManager) o separar todo y dejar que cada Adaptador amplíe SQLiteOpenHelper?
¿Cómo debería diseñar proveedores de contenido para múltiples tablas? Extendiendo la pregunta anterior, ¿debería usar un proveedor de contenido para toda la aplicación, o debería crear proveedores separados para eventos y lugares?
La mayoría de los ejemplos que encuentro solo tratan con aplicaciones de una sola tabla, por lo que agradecería cualquier sugerencia aquí.
Nota: Esta es una aclaración / modificación a la respuesta proporcionada por Opy.
Este enfoque subdivide cada uno de los métodos insert
, delete
, update
y getType
con declaraciones switch para manejar cada una de sus tablas individuales. Utilizará un CASO para identificar cada tabla (o uri) a la que se hará referencia. Cada CASE luego se asigna a una de sus tablas o URI. Por ejemplo, se selecciona TABLE1 o URI1 en CASE # 1, etc. para todas las tablas que emplea su aplicación.
Aquí hay un ejemplo del enfoque. Esto es para el método de inserción. Se implementa de forma un poco diferente a la de Opy, pero realiza la misma función. Puede seleccionar el estilo que prefiera. También quería asegurarme de que insert devuelva un valor incluso si la inserción de la tabla falla. En ese caso, devuelve un -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]
Recomiendo ver el código fuente para Android 2.x ContactProvider. (Que se puede encontrar en línea). Manejan consultas de tablas cruzadas al proporcionar vistas especializadas en las que luego ejecuta consultas en el back-end. En la parte frontal, son accesibles para la persona que llama a través de diferentes URI a través de un único proveedor de contenido. Probablemente también desee proporcionar una clase o dos para mantener constantes para los nombres de campo de la tabla y las cadenas de URI. Estas clases se pueden proporcionar como una API incluida o como una gota en la clase, y harán que sea mucho más fácil para la aplicación que consume el uso.
Es un poco complejo, por lo que es posible que también desee ver cómo funciona el calendario para hacerse una idea de lo que hace y lo que no necesita.
Solo debe necesitar un adaptador de base de datos único y un único proveedor de contenido por base de datos (no por tabla) para hacer la mayor parte del trabajo, pero puede usar múltiples adaptadores / proveedores si realmente lo desea. Simplemente hace las cosas un poco más complicadas.
Un ContentProvider
puede servir varias tablas, pero deben estar relacionadas de alguna manera. Marcará la diferencia si tiene la intención de sincronizar a sus proveedores. Si desea sincronizar por separado, digamos Contactos, Correo o Calendario, necesitará diferentes proveedores para cada uno de ellos, incluso si terminan en la misma base de datos o se sincronizan con el mismo servicio, porque los Adaptadores de Sincronización están vinculados directamente a un proveedor en particular.
Por lo que puedo decir, solo se puede usar un solo SQLiteOpenHelper por base de datos, ya que almacena su metainformación en una tabla dentro de la base de datos. Entonces, si sus ContentProviders
acceden a la misma base de datos, tendrá que compartir el helper de alguna manera.