Content Provider é um componente Android que fornece uma interface unificada para acesso a dados entre aplicações. Ele abstrai o armazenamento físico (SQLite, arquivos, fontes de rede) e permite a troca segura de informações através do ContentResolver. De acordo com o Android Developer Guide, 2026, o Content Provider é um dos quatro componentes principais de uma aplicação Android, juntamente com Activity, Service e BroadcastReceiver. Sua tarefa é disponibilizar dados para outras aplicações com controle de permissões de leitura e escrita.
Pontos principais
Content Provider é um componente Android que gerencia o acesso a um armazenamento de dados centralizado e o disponibiliza para outras aplicações através de uma interface de contrato unificada. Ele oculta os detalhes de implementação do armazenamento: os dados podem ser armazenados em SQLite, no sistema de arquivos, na nuvem ou ser o resultado de uma requisição de rede.
O Android inclui Content Providers integrados para dados do sistema — ContactsContract, MediaStore, CalendarContract, CallLog. Aplicações de terceiros também podem criar seus próprios provedores para troca segura de dados. Cada provedor é registrado no AndroidManifest.xml com uma authority — uma string única que forma a primeira parte da URI.
O Content Provider opera em um modelo cliente-servidor. O provedor atua como um servidor que implementa seis métodos obrigatórios: query, insert, update, delete, getType e onCreate. O cliente (outra aplicação) acessa o provedor através do ContentResolver, que traduz as chamadas nos métodos correspondentes do provedor através do mecanismo IPC do Android.
Cada Content Provider é identificado por uma URI do esquema content://. Por exemplo, content://com.example.app.provider/items. A primeira parte authority (com.example.app.provider) é vinculada à classe do provedor no manifesto. O caminho /items aponta para uma tabela, enquanto /items/5 aponta para um registro específico com ID=5.
Quando uma aplicação chama ContentResolver.query(URI), o Android verifica as permissões do pacote chamador, encontra o provedor pela authority e inicia seu processo se ele ainda não estiver em execução. O provedor executa a consulta e retorna um Cursor — um objeto que contém o resultado e permite ao cliente iterar sobre os registros.
A classe ContentProvider requer a implementação de seis métodos abstratos. Cada método aceita uma URI e retorna um resultado correspondente ao tipo de operação. O sistema chama esses métodos de qualquer processo, portanto eles devem ser thread-safe e não bloquear a execução por muito tempo.
O método query aceita uma URI, uma matriz de colunas projection, uma string selection com argumentos e uma ordem de classificação. Ele retorna um Cursor com dados. Na implementação, você precisa analisar a URI usando UriMatcher e executar a consulta SQL correspondente no banco de dados.
Esses métodos modificam dados no armazenamento. insert recebe ContentValues — pares chave-valor — e retorna a URI do novo registro. update e delete aceitam uma selection para filtrar registros e retornam o número de linhas afetadas. Após alterar os dados, o provedor deve notificar através de ContentResolver.notifyChange.
| Método | Finalidade | Retorno |
|---|---|---|
| query | Obter dados por URI | Cursor ou null |
| insert | Adicionar novo registro | URI do novo registro |
| update | Atualizar registros existentes | int (qtd. de linhas) |
| delete | Excluir registros | int (qtd. de linhas) |
| getType | Tipo MIME para URI | String |
| onCreate | Inicialização do provedor | boolean |
ContentResolver é um ponto de acesso único para trabalhar com todos os Content Providers no sistema. A aplicação cliente nunca chama os métodos do provedor diretamente — apenas através do ContentResolver, que o Android obtém do contexto. As operações CRUD no ContentResolver têm os mesmos nomes que no provedor, mas aceitam URIs em vez de referências diretas.
Para analisar URIs de entrada dentro do provedor, usa-se UriMatcher. Ele permite mapear uma URI para um código numérico — por exemplo, a URI content://authority/items produz o código 1, e content://authority/items/# produz o código 2. Isso elimina a necessidade de análise manual da string URI em cada método.
// Usando ContentResolver para acessar contatos
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("Contatos", "Nome: $name")
}
}
O Cursor deve ser sempre fechado após o uso — no exemplo acima, a função use (extensão do Kotlin) faz isso. Se o Cursor não for fechado, ocorre um vazamento de memória porque ele mantém uma referência aos dados no pool de Binder. Para cenários de UI, use CursorLoader ou Room com LiveData/Flow.
Criar seu próprio Content Provider começa com a extensão da classe ContentProvider. O provedor trabalha com um banco de dados SQLite através do SQLiteOpenHelper e usa UriMatcher para determinar o tipo de consulta. Considere uma implementação mínima para gerenciar uma lista de notas.
O provedor é registrado no AndroidManifest.xml dentro da tag application. O atributo authorities define um identificador único, e exported determina se outras aplicações podem acessar o provedor. Sem exported=true, o provedor é acessível apenas dentro da sua aplicação.
// Exemplo 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 brevidade
}
Após criar a classe do provedor, ela deve ser registrada no manifesto com os atributos android:authorities e android:exported (true se o provedor for público). O sistema cria uma instância do provedor no primeiro acesso — isso ocorre na thread da UI, portanto o onCreate deve executar rapidamente.
O Content Provider permite gerenciar o acesso aos dados em dois níveis: permissões de leitura e permissões de escrita. Elas são definidas no manifesto com os atributos android:readPermission e android:writePermission. Se a aplicação cliente não tiver a permissão correspondente, o sistema rejeita a chamada com uma SecurityException.
O Android suporta permissões temporárias através das flags FLAG_GRANT_READ_URI_PERMISSION e FLAG_GRANT_WRITE_URI_PERMISSION. Isso é útil quando uma aplicação passa uma URI de arquivo para outra aplicação via Intent — o destinatário obtém acesso apenas àquela URI específica por um tempo limitado. O sistema revoga a permissão temporária após a aplicação receptora terminar.
Para provedores do sistema, o Android exige a especificação de permissões específicas no manifesto da aplicação. Por exemplo, acessar contatos requer READ_CONTACTS, e acessar o calendário requer READ_CALENDAR. A partir do Android 6, essas permissões são solicitadas em tempo de execução, não durante a instalação.
Perguntas frequentes
Content Provider é um componente Android que fornece uma interface padrão para troca de dados entre aplicações através do ContentResolver. Ele abstrai o método de armazenamento (SQLite, arquivos, rede) e garante acesso seguro aos dados com controle de permissões de leitura e escrita.
Authority é uma string identificadora única do provedor especificada no AndroidManifest.xml. Ela forma a primeira parte da URI content://authority/path e é usada pelo sistema para rotear chamadas do ContentResolver ao provedor correto. A authority deve ser única entre todas as aplicações no dispositivo.
UriMatcher mapeia URIs para códigos numéricos. Você adiciona padrões via addURI, depois chama match para obter o código de uma URI de entrada. Isso permite que os métodos query, insert, update e delete determinem qual tabela ou registro está sendo solicitado e realizem a operação correspondente no banco de dados.
Sim, o Cursor deve ser sempre fechado após o uso. Se o Cursor não for fechado, ocorre um vazamento de memória porque ele mantém uma referência Binder aos dados do provedor. Em Kotlin, use a função use para fechamento automático, e em Java — try-with-resources ou cursor.close() em um bloco finally.
Content Provider é um componente para acesso a dados entre aplicações, enquanto SQLiteDatabase é um mecanismo de armazenamento interno para uma única aplicação. O Content Provider fornece uma interface URI e controle de permissões, enquanto o SQLiteDatabase trabalha diretamente com o banco de dados sem mecanismos de segurança em nível de sistema operacional.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também