Content Provider es un componente de Android que proporciona una interfaz unificada para el acceso a datos entre aplicaciones. Abstrae el almacenamiento físico (SQLite, archivos, fuentes de red) y permite el intercambio seguro de información a través de ContentResolver. Según Android Developer Guide, 2026, Content Provider es uno de los cuatro componentes principales de una aplicación Android, junto con Activity, Service y BroadcastReceiver. Su tarea es hacer que los datos estén disponibles para otras aplicaciones con control de permisos de lectura y escritura.
Puntos clave
Content Provider es un componente de Android que gestiona el acceso a un almacén de datos centralizado y lo proporciona a otras aplicaciones a través de una interfaz de contrato unificada. Oculta los detalles de implementación del almacenamiento: los datos pueden almacenarse en SQLite, en el sistema de archivos, en la nube o ser el resultado de una solicitud de red.
Android incluye Content Providers incorporados para datos del sistema — ContactsContract, MediaStore, CalendarContract, CallLog. Las aplicaciones de terceros también pueden crear sus propios proveedores para el intercambio seguro de datos. Cada proveedor se registra en AndroidManifest.xml con una authority — una cadena única que forma la primera parte de la URI.
Content Provider opera en un modelo cliente-servidor. El proveedor actúa como servidor que implementa seis métodos obligatorios: query, insert, update, delete, getType y onCreate. El cliente (otra aplicación) accede al proveedor a través de ContentResolver, que traduce las llamadas a los métodos correspondientes del proveedor mediante el mecanismo IPC de Android.
Cada Content Provider se identifica mediante una URI del esquema content://. Por ejemplo, content://com.example.app.provider/items. La primera parte authority (com.example.app.provider) se vincula a la clase del proveedor en el manifiesto. La ruta /items apunta a una tabla, mientras que /items/5 apunta a un registro específico con ID=5.
Cuando una aplicación llama a ContentResolver.query(URI), Android verifica los permisos del paquete llamante, encuentra el proveedor por su authority e inicia su proceso si aún no está en ejecución. El proveedor ejecuta la consulta y devuelve un Cursor — un objeto que contiene el resultado y permite al cliente iterar sobre los registros.
La clase ContentProvider requiere la implementación de seis métodos abstractos. Cada método acepta una URI y devuelve un resultado correspondiente al tipo de operación. El sistema llama a estos métodos desde cualquier proceso, por lo que deben ser seguros para subprocesos y no bloquear la ejecución durante mucho tiempo.
El método query acepta una URI, una matriz de columnas projection, una cadena selection con argumentos y un orden de clasificación. Devuelve un Cursor con datos. En la implementación, es necesario analizar la URI con UriMatcher y ejecutar la consulta SQL correspondiente en la base de datos.
Estos métodos modifican datos en el almacén. insert recibe ContentValues — pares clave-valor — y devuelve la URI del nuevo registro. update y delete aceptan una selección para filtrar registros y devuelven la cantidad de filas afectadas. Después de cambiar los datos, el proveedor debe notificarlo a través de ContentResolver.notifyChange.
| Método | Propósito | Retorno |
|---|---|---|
| query | Obtener datos por URI | Cursor o null |
| insert | Agregar un nuevo registro | URI del nuevo registro |
| update | Actualizar registros existentes | int (cant. de filas) |
| delete | Eliminar registros | int (cant. de filas) |
| getType | Tipo MIME para URI | String |
| onCreate | Inicialización del proveedor | boolean |
ContentResolver es un punto de acceso único para trabajar con todos los Content Providers del sistema. La aplicación cliente nunca llama a los métodos del proveedor directamente — solo a través de ContentResolver, que Android obtiene del contexto. Las operaciones CRUD en ContentResolver tienen los mismos nombres que en el proveedor, pero aceptan URI en lugar de referencias directas.
Para analizar las URI entrantes dentro del proveedor, se utiliza UriMatcher. Permite asignar una URI a un código numérico — por ejemplo, la URI content://authority/items produce el código 1, y content://authority/items/# produce el código 2. Esto elimina la necesidad de analizar manualmente la cadena URI en cada método.
// Usando ContentResolver para acceder a contactos
val uri = ContactsContract.Contacts.CONTENT_URI
val cursor = contentResolver.query(
uri,
arrayOf(ContactsContract.Contacts.DISPLAY_NAME),
null, null, null
)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndexOrThrow(
ContactsContract.Contacts.DISPLAY_NAME
))
Log.d("Contactos", "Nombre: $name")
}
}
El Cursor debe cerrarse siempre después de su uso — en el ejemplo anterior, la función use (extensión de Kotlin) lo hace. Si el Cursor no se cierra, se produce una fuga de memoria porque mantiene una referencia a los datos en el grupo de Binder. Para escenarios de UI, use CursorLoader o Room con LiveData/Flow.
La creación de su propio Content Provider comienza con la extensión de la clase ContentProvider. El proveedor trabaja con una base de datos SQLite a través de SQLiteOpenHelper y utiliza UriMatcher para determinar el tipo de consulta. Considere una implementación mínima para gestionar una lista de notas.
El proveedor se registra en AndroidManifest.xml dentro de la etiqueta application. El atributo authorities establece un identificador único, y exported determina si otras aplicaciones pueden acceder al proveedor. Sin exported=true, el proveedor solo es accesible dentro de su aplicación.
// Ejemplo de Content Provider para notas
class NotesProvider : ContentProvider() {
companion object {
const val AUTHORITY = "com.example.app.notes"
const val NOTES_PATH = "notes"
const val NOTES_URI = "content://$AUTHORITY/$NOTES_PATH"
const val NOTES_ID = "content://$AUTHORITY/$NOTES_PATH/#"
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(AUTHORITY, NOTES_PATH, 1)
addURI(AUTHORITY, "$NOTES_PATH/#", 2)
}
}
override fun query(uri: Uri, projection: Array<String>?,
selection: String?, args: Array<String>?, sort: String?): Cursor? {
return when (uriMatcher.match(uri)) {
1 -> dbHelper.readableDatabase.query(TABLE_NOTES,
projection, selection, args, null, null, sort)
2 -> dbHelper.readableDatabase.query(TABLE_NOTES,
projection, "_id=?", arrayOf(uri.lastPathSegment), null, null, null)
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val id = dbHelper.writableDatabase.insert(TABLE_NOTES, null, values)
context?.contentResolver?.notifyChange(uri, null)
return ContentUris.withAppendedId(uri, id)
}
override fun delete(uri: Uri, selection: String?, args: Array<String>?): Int {
val count = dbHelper.writableDatabase.delete(TABLE_NOTES, selection, args)
context?.contentResolver?.notifyChange(uri, null)
return count
}
// getType, update, onCreate omitidos por brevedad
}
Después de crear la clase del proveedor, debe registrarse en el manifiesto con los atributos android:authorities y android:exported (true si el proveedor es público). El sistema crea una instancia del proveedor al primer acceso — esto ocurre en el hilo de la UI, por lo que onCreate debe ejecutarse rápidamente.
Content Provider permite gestionar el acceso a los datos en dos niveles: permisos de lectura y permisos de escritura. Se establecen en el manifiesto con los atributos android:readPermission y android:writePermission. Si la aplicación cliente no tiene el permiso correspondiente, el sistema rechaza la llamada con una SecurityException.
Android admite permisos temporales mediante las banderas FLAG_GRANT_READ_URI_PERMISSION y FLAG_GRANT_WRITE_URI_PERMISSION. Esto es útil cuando una aplicación pasa una URI de archivo a otra aplicación a través de un Intent — el destinatario obtiene acceso solo a esa URI específica durante un tiempo limitado. El sistema revoca el permiso temporal después de que la aplicación receptora finaliza.
Para los proveedores del sistema, Android requiere especificar permisos concretos en el manifiesto de la aplicación. Por ejemplo, acceder a los contactos requiere READ_CONTACTS, y acceder al calendario requiere READ_CALENDAR. A partir de Android 6, estos permisos se solicitan en tiempo de ejecución, no durante la instalación.
Preguntas frecuentes
Content Provider es un componente de Android que proporciona una interfaz estándar para el intercambio de datos entre aplicaciones a través de ContentResolver. Abstrae el método de almacenamiento (SQLite, archivos, red) y garantiza un acceso seguro a los datos con control de permisos de lectura y escritura.
Authority es una cadena identificadora única del proveedor que se especifica en AndroidManifest.xml. Forma la primera parte de la URI content://authority/path y el sistema la utiliza para enrutar las llamadas de ContentResolver al proveedor correcto. La authority debe ser única entre todas las aplicaciones del dispositivo.
UriMatcher asigna URI a códigos numéricos. Agrega patrones mediante addURI, luego llama a match para obtener el código de una URI entrante. Esto permite que los métodos query, insert, update y delete determinen qué tabla o registro se solicita y realicen la operación correspondiente en la base de datos.
Sí, el Cursor debe cerrarse siempre después de su uso. Si no se cierra, se produce una fuga de memoria porque mantiene una referencia Binder a los datos del proveedor. En Kotlin, use la función use para el cierre automático, y en Java — try-with-resources o cursor.close() en un bloque finally.
Content Provider es un componente para el acceso a datos entre aplicaciones, mientras que SQLiteDatabase es un mecanismo de almacenamiento interno para una sola aplicación. Content Provider proporciona una interfaz URI y control de permisos, mientras que SQLiteDatabase trabaja directamente con la base de datos sin mecanismos de seguridad a nivel de sistema operativo.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también