android - contentprovider - Biblioteca de persistencia de salas y proveedor de contenidos.
persistencia android (4)
Últimos días he pasado veces aprendiendo nuevos componentes de la arquitectura de Android . Después de seguir algunas publicaciones de blog, documentación y tutoriales, todos los componentes se me aclararon. Pero de repente me di cuenta de qué pasa con nuestro viejo proveedor de contenido amigo. Puede que parezca una tontería, porque antes de escribir esta pregunta he pasado bastante tiempo buscando, ¿Soy el único que se me ocurrió esta pregunta? No tenía ninguna solución útil. De todos modos, aquí está, si quiero crear una aplicación con base de datos local, obviamente ahora elegiré los nuevos Componentes de Arquitectura (datos en vivo, modelo de vista, sala) sin pensar que esto será muy útil para hacer que la aplicación sea 10x robusta. Pero si quiero que mis datos de base de datos sean accesibles a otra aplicación, por ejemplo, al widget. ¿Cómo integro el proveedor de contenido con Room?
Si quiero crear una aplicación con base de datos local, obviamente elegiré nuevos Componentes de Arquitectura (datos en vivo, modelo de vista, sala)
No usaría el término "obviamente" allí. Los Componentes de Arquitectura son una opción, pero no un requisito.
Pero si quiero que mis datos de base de datos sean accesibles a otra aplicación, por ejemplo, al widget. ¿Cómo integro el proveedor de contenido con Room?
Un widget de aplicación no está relacionado con un ContentProvider
. En mi humilde opinión, muy pocas aplicaciones deberían estar exponiendo bases de datos a terceros a través de ContentProvider
, y ninguna aplicación debería usar un ContentProvider
únicamente para fines internos.
Dicho esto, tienes algunas opciones:
No utilice la sala, al menos para las tablas que se expondrán a través del
ContentProvider
Use Room para propósitos internos, pero luego use técnicas de programación SQLite clásicas para
ContentProvider
, llamando agetOpenHelper()
en suRoomDatabase
Use Room en el
ContentProvider
, escriba su propio código para crear unMatrixCursor
desde las entidades de Room que recupere (paraquery()
) o cree las entidades para usar con otras operaciones (parainsert()
,update()
,delete()
, etc.)
Último post pero me topé en el mismo tema recientemente. Finalmente, terminó usando la misma instancia de la base de datos de sala para el propósito del proveedor de contenido local.
Por lo tanto, la aplicación utiliza la base de datos de la sala como de costumbre y el proveedor de contenido "envuelve" la base de datos de la sala con el "ayudante abierto" de la siguiente manera:
class DatabaseProvider : ContentProvider() {
override fun onCreate(): Boolean {
return true
}
override fun query(uri: Uri?, projection: Array<out String?>?, selection: String?, selectionArgs: Array<out String?>?, sortOrder: String?): Cursor? {
val db = roomDatabase.openHelper.readableDatabase
db.query(...)
}
override fun insert(uri: Uri?, values: ContentValues?): Uri? {
val db = roomDatabase.openHelper.writableDatabase
db.insert(...)
}
override fun update(uri: Uri?, values: ContentValues?, selection: String?, selectionArgs: Array<out String?>?): Int {
val db = roomDatabase.openHelper.writableDatabase
db.update(...)
}
override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String?>?): Int {
val db = roomDatabase.openHelper.writableDatabase
db.delete(...)
}
override fun getType(uri: Uri?): String? {
}
}
La biblioteca de la sala no tiene ningún soporte especial para el proveedor de contenido. Solo puede escribir el Proveedor de contenido por su cuenta y luego usar Room para consultar una base de datos.
Si desea usar los componentes de la arquitectura de Android y desea trabajar con proveedores de contenido basados en SQLite, considere usar la biblioteca de persistencia Kripton : le permite generar datos en vivo a partir de consultas de base de datos, generar un proveedor de contenido para usted y mucho más. Menos pero no último: ¿por qué tiene que escribir todo el SQL, cuando solo necesita escribir las condiciones donde?
Para ser claros, soy el autor de Kripton Persistence Library. Lo escribí porque no encontré una biblioteca única que se ajustara a todas mis necesidades en términos de gestión de persistencia (y sí, porque me gusta programar).
Escribí una versión convertida de Google Content Provider Sample con Kripton. Puedes encontrarlo here .
Solo para simplificar la lectura. Con Kripton, solo necesita definir una interfaz DAO. Proveedor de contenido será generado por las anotaciones. El mismo DAO convertido en Kripton será:
@BindContentProviderPath(path = "cheese")
@BindDao(Cheese.class)
public interface CheeseDao {
@BindSqlSelect(fields="count(*)")
int count();
@BindContentProviderEntry
@BindSqlInsert
long insert(String name);
@BindContentProviderEntry()
@BindSqlSelect
List<Cheese> selectAll();
@BindContentProviderEntry(path = "${id}")
@BindSqlSelect(where ="id=${id}")
Cheese selectById(long id);
@BindContentProviderEntry(path = "${id}")
@BindSqlDelete(where ="id=${id}")
int deleteById(long id);
@BindContentProviderEntry(path = "${cheese.id}")
@BindSqlUpdate(where="id=${cheese.id}")
int update(Cheese cheese);
}
El proveedor de contenido generado expone el método de DAO con URI. Para su aclaración, pongo aquí solo el JavaDoc generado (siempre por Kripton).
Más información sobre Kripton en su wiki , mi sitio y en mis artículos .
Tuve la misma pregunta por cierto. Y encontré una muestra here que responde a mi pregunta. Espero que haga lo mismo contigo.
En resumen, esto está en el objeto DAO que se llamaría desde el método query()
del proveedor de contenido.
/**
* Select all cheeses.
*
* @return A {@link Cursor} of all the cheeses in the table.
*/
@Query("SELECT * FROM " + Cheese.TABLE_NAME)
Cursor selectAll();
Observe cómo devuelve el objeto Cursor
. En otras operaciones, puede ver por sí mismo con más detalle en la muestra.
Esta es la opción número 3 en la respuesta de @CommonsWare, creo.