A classe BitmapFactory no ecossistema Android disponibiliza quatro abordagans principais para a decodificação de imagens em objetos Bitmap:
decodeFile: Realiza a leitura direta a partir do sistema de arquivos.decodeResource: Extrai imagens dos assets ou pastas de recursos do aplicativo.decodeByteArray: Processa imagens a partir de arrays de bytes.decodeStream: Lê dados através de um fluxo de entrada (InputStream). Esta é a implementação subjacente utilizada pordecodeFileedecodeResource.
Carregar imagens de alta resolução dirteamente na memória frequentemente resulta em exceções de estouro de memória (OOM). Para mitigar esse problema, utiliza-se a técnica de subamostragem (downsampling) através do parâmetro inSampleSize presente na classe BitmapFactory.Options.
O fluxo de trabalho para um carregamento otimizado envolve três etapas fundamentais:
- Configurar a propriedade
inJustDecodeBoundscomotrue. Isso instrui o decodificador a extrair apenas os metadados da imagem (dimensões originais) sem alocar a matriz de pixels na memória. - Obter as dimensões brutas (
outWidtheoutHeight) e compará-las com as dimensões exigidas pela interface do usuário para calcular a taxa de amostragem ideal. - Redefinir
inJustDecodeBoundsparafalse, aplicar o fator de escala calculado e executar a decdoificação final.
Abaixo está a implementação refatorada para realizar esse processo:
public static Bitmap loadScaledBitmap(Resources resources, int imageResId, int targetW, int targetH) {
BitmapFactory.Options decodingOptions = new BitmapFactory.Options();
// Primeira passagem: extração de metadados sem alocação de memória
decodingOptions.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, imageResId, decodingOptions);
// Cálculo da taxa de redução baseado nas dimensões originais e alvo
int scaleFactor = computeSamplingRate(
decodingOptions.outWidth,
decodingOptions.outHeight,
targetW,
targetH
);
// Segunda passagem: decodificação real aplicando a subamostragem
decodingOptions.inSampleSize = scaleFactor;
decodingOptions.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(resources, imageResId, decodingOptions);
}
A função auxiliar para o cálculo matemático do fator de escala foi isolada para receber as dimensões diretamente, operando da seguinte maneira:
private static int computeSamplingRate(int rawWidth, int rawHeight, int reqWidth, int reqHeight) {
// Prevenção contra argumentos inválidos
if (reqWidth <= 0 || reqHeight <= 0) {
return 1;
}
int sampleRate = 1;
// A subamostragem só é necessária se a imagem original for maior que o alvo
if (rawHeight > reqHeight || rawWidth > reqWidth) {
int tempWidth = rawWidth;
int tempHeight = rawHeight;
// Determina a maior potência de 2 que mantém a imagem maior ou igual ao alvo
while ((tempWidth / 2) >= reqWidth && (tempHeight / 2) >= reqHeight) {
sampleRate *= 2;
tempWidth /= 2;
tempHeight /= 2;
}
}
return sampleRate;
}