🚀 5.3 Crie um Content Provider para o seu aplicativo

Embora o Room simplifique a persistência interna, um ContentProvider é necessário se você deseja que outros aplicativos acessem seus dados de viagens. No Android moderno, integramos o ContentProvider diretamente com a nossa base de dados Room.

Definindo o Contrato (BoaViagemContract)

O contrato centraliza as URIs e nomes de colunas, facilitando o uso por terceiros:

public final class BoaViagemContract {
    public static final String AUTHORITY = "br.com.casadocodigo.boaviagem.provider";
    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
    
    public static final class Viagem {
        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "viagem");
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.boaviagem.viagem";
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.boaviagem.viagem";
        
        public static final String DESTINO = "destino";
        public static final String ORCAMENTO = "orcamento";
    }
}

Implementando o Provedor com Room

No Android Studio 2023.1, nossa classe BoaViagemProvider utiliza o singleton do AppDatabase para obter os dados. Como o ContentProvider exige o retorno de um Cursor, acessamos o banco de dados subjacente do Room:

public class BoaViagemProvider extends ContentProvider {
 
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        uriMatcher.addURI(AUTHORITY, "viagem", 1);
        uriMatcher.addURI(AUTHORITY, "viagem/#", 2);
    }
 
    @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        var db = AppDatabase.getDatabase(getContext()).getOpenHelper().getReadableDatabase();
        var queryBuilder = new SupportSQLiteQueryBuilder("viagem")
                .columns(projection)
                .selection(selection, selectionArgs)
                .orderBy(sortOrder);
 
        if (uriMatcher.match(uri) == 2) {
            queryBuilder.selection("id = ?", new Object[]{uri.getLastPathSegment()});
        }
 
        return db.query(queryBuilder.create());
    }
 
    // Métodos insert, update and delete seguem lógica similar
    @Override
public boolean onCreate() { return true; }
    
    @Override
public String getType(Uri uri) {
        return (uriMatcher.match(uri) == 1) ? Viagem.CONTENT_TYPE : Viagem.CONTENT_ITEM_TYPE;
    }
}

IMPORTANT

Compatibilidade Room e Cursor: O Room é projetado para retornar objetos, mas o ContentProvider exige Cursors. Ao usar getOpenHelper().getReadableDatabase(), você acessa a engine SQLite do Room mantendo a consistência dos dados e aproveitando a estrutura já definida.

TIP

Não esqueça de registrar o provedor no AndroidManifest.xml. No Android 11+ (API 30), outros apps só verão seu provedor se declararem <queries> com a autoridade correta no manifesto deles.


⬅️ Capítulo Anterior | Próximo Capítulo ➡️