Recurso que possibilita compartilhar dados privados entre aplicativos.
Para mais detalhes: GOOGLE DEVELOPERS. Fundamentos do provedor de conteúdo. Disponível em: https://developer.android.com/guide/topics/providers/content-provider-basics?hl=pt-br. Acesso em: 01 set. 2025.
Content Provider
Exemplo 01: (Adaptado de: Stack overflow. Android: não estou obtendo nenhum contato da lista de contatos. 2018. Disponível em: https://stackoverflow.com/questions/53956496/android-not-getting-any-contacts-from-contact-list. Pergunta feita pelo usuário https://stackoverflow.com/users/4951663/mohit-suthar e respondida pelo https://stackoverflow.com/users/4390987/%e0%a5%90-rakesh-kumar.):
-
No arquivo AndroidManifest.xml, deve-se acrescentar a tag <uses-permission android:name="android.permission.READ_CONTACTS" />
-
Contato.java
public class Contato { private int id; private String nome, fone; public Contato(int id, String nome, String fone) { this.id = id; this.nome = nome; this.fone = fone; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getFone() { return fone; } public void setFone(String fone) { this.fone = fone; } @Override public String toString() { return "Contato{" + "id=" + id + ", nome='" + nome + '\'' + ", fone='" + fone + '\'' + '}'; } }
-
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margin="10dp" tools:context=".MainActivity"> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/lista"/> </LinearLayout>
-
MainActivity.java
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.Manifest; import android.content.ContentResolver; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.ContactsContract; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private ListView lista; private ArrayAdapter<Contato> dadosAdapter; private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lista = findViewById(R.id.lista); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS); } else { carregarContatos(); } } private void carregarContatos() { ArrayList<Contato> contatos = obterDados(); dadosAdapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, contatos); lista.setAdapter(dadosAdapter); lista.setOnItemClickListener(this); } public ArrayList<Contato> obterDados() { ArrayList<Contato> dados = new ArrayList<>(); Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; String[] projection = { ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER }; ContentResolver resolver = getContentResolver(); Cursor cursor = resolver.query(uri, projection, null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC"); if (cursor != null) { int idIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID); int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME); int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER); while (cursor.moveToNext()) { int id = cursor.getInt(idIndex); String nome = cursor.getString(nameIndex); String fone = cursor.getString(phoneIndex); dados.add(new Contato(id, nome, fone)); } cursor.close(); } return dados; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Contato item = (Contato) parent.getItemAtPosition(position); Toast.makeText(MainActivity.this, item.toString(), Toast.LENGTH_SHORT).show(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { carregarContatos(); } else { Toast.makeText(this, "Permissão negada!!!!", Toast.LENGTH_SHORT).show(); } } } }
Exemplo 02: (criar dois apps, um para prover o conteúdo e outro para consumir)
App provedor
-
No arquivo AndroidManifest.xml acrescentar <provider android:name=".DadosProvider" android:authorities="nomeDaAutoridade" android:exported="true" android:grantUriPermissions="true"/>
-
DadosProvider.java
import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; public class DadosProvider extends ContentProvider { private static final int BANCO_VERSAO = 1; private static final String BANCO_NOME = "meu_banco.db"; private static final String BANCO_TABELA = "contato"; public static final String ID = "_id"; public static final String NOME = "nome"; public static final String TELEFONE = "telefone"; private static final String CRIA_TABELA = "CREATE TABLE " + BANCO_TABELA + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + NOME + " TEXT, " + TELEFONE + " TEXT)"; private static final String DELETA_TABELA = "DROP TABLE IF EXISTS " + BANCO_TABELA; private SQLiteDatabase banco; private static final String TAG = DadosProvider.class.getSimpleName(); public static final String AUTHORITY = "nomeDaAutoridade"; public static final String PATH = "dados"; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH); private static final int CODIGO_URI_TODOS = 1; private static final UriMatcher URI_MATCHER; static { URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); URI_MATCHER.addURI(AUTHORITY, PATH, CODIGO_URI_TODOS); } @Override public boolean onCreate() { Context context = getContext(); BancoHelper helper = new BancoHelper(context); banco = helper.getWritableDatabase(); if (banco != null) { Log.i(TAG, "Provedor criado"); return true; } return false; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { SQLiteQueryBuilder sqb = new SQLiteQueryBuilder(); sqb.setTables(BANCO_TABELA); Cursor cursor = sqb.query(banco, projection, selection, selectionArgs, null, null, sortOrder); if (cursor != null) { cursor.setNotificationUri(getContext().getContentResolver(), uri); } Log.i(TAG, "Query executada"); return cursor; } @Nullable @Override public String getType(@NonNull Uri uri) { switch (URI_MATCHER.match(uri)) { case CODIGO_URI_TODOS: return "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + PATH; default: throw new IllegalArgumentException("URI inválida: " + uri); } } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { long id = banco.insert(BANCO_TABELA, null, values); if (id > 0) { Uri uriID = ContentUris.withAppendedId(CONTENT_URI, id); getContext().getContentResolver().notifyChange(uriID, null); Log.i(TAG, "Dados inseridos: ID = " + id); return uriID; } throw new SQLException("Erro ao inserir registro em " + uri); } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { int count; switch (URI_MATCHER.match(uri)) { case CODIGO_URI_TODOS: count = banco.delete(BANCO_TABELA, selection, selectionArgs); Log.i(TAG, "Registros deletados: " + count); break; default: throw new IllegalArgumentException("URI inválida para delete: " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { int count; switch (URI_MATCHER.match(uri)) { case CODIGO_URI_TODOS: count = banco.update(BANCO_TABELA, values, selection, selectionArgs); Log.i(TAG, "Registros alterados: " + count); break; default: throw new IllegalArgumentException("URI inválida para update: " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } private static class BancoHelper extends SQLiteOpenHelper { BancoHelper(Context context) { super(context, BANCO_NOME, null, BANCO_VERSAO); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CRIA_TABELA); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(DELETA_TABELA); onCreate(db); } } }
-
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <Button android:id="@+id/btnAdicionar" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Adicionar Contato" /> <Button android:id="@+id/btnMostrar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:text="Mostrar Contatos" /> <ListView android:id="@+id/lista" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="12dp" android:divider="@android:color/darker_gray" android:dividerHeight="1dp"/> </LinearLayout>
-
MainActivity.java
import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import java.util.Random; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private ListView lista; private SimpleCursorAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnAdicionar = findViewById(R.id.btnAdicionar); Button btnMostrar = findViewById(R.id.btnMostrar); lista = findViewById(R.id.lista); String[] colunas = new String[]{DadosProvider.NOME, DadosProvider.TELEFONE}; int[] views = new int[]{android.R.id.text1, android.R.id.text2}; adapter = new SimpleCursorAdapter( this, android.R.layout.simple_list_item_2, null, colunas, views, 0 ); lista.setAdapter(adapter); btnAdicionar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ContentValues values = new ContentValues(); values.put(DadosProvider.NOME, "Contato " + new Random().nextInt(100)); values.put(DadosProvider.TELEFONE, "9999-" + new Random().nextInt(9999)); Uri uri = getContentResolver().insert(DadosProvider.CONTENT_URI, values); Log.i(TAG, "Inserido em: " + uri); } }); btnMostrar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { atualizarLista(); } }); } private void atualizarLista() { Cursor cursor = getContentResolver().query( DadosProvider.CONTENT_URI, null, null, null, null ); adapter.changeCursor(cursor); } @Override protected void onDestroy() { super.onDestroy(); if (adapter != null && adapter.getCursor() != null) { adapter.getCursor().close(); } } }
AppCliente
-
No AndroidManifest.xml acrescente a tag <queries> <provider android:authorities="nomeDaAutoridade" /> </queries>
-
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <Button android:id="@+id/btnMostrar" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Mostrar Contatos" /> <ListView android:id="@+id/lista" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="12dp" android:divider="@android:color/darker_gray" android:dividerHeight="1dp"/> </LinearLayout>
-
MainActivity.java
import androidx.appcompat.app.AppCompatActivity; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleCursorAdapter; public class MainActivity extends AppCompatActivity { private ListView lista; private SimpleCursorAdapter adapter; private static final String AUTHORITY = "nomeDaAutoridade"; private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/contatos"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnMostrar = findViewById(R.id.btnMostrar); lista = findViewById(R.id.lista); String[] colunas = new String[]{"nome", "telefone"}; int[] views = new int[]{android.R.id.text1, android.R.id.text2}; adapter = new SimpleCursorAdapter( this, android.R.layout.simple_list_item_2, null, colunas, views, 0 ); lista.setAdapter(adapter); btnMostrar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { atualizarLista(); } }); } private void atualizarLista() { Cursor cursor = getContentResolver().query( CONTENT_URI, null, null, null, null ); adapter.changeCursor(cursor); } @Override protected void onDestroy() { super.onDestroy(); if (adapter != null && adapter.getCursor() != null) { adapter.getCursor().close(); } } }