画像のURLがたくさんあります。これらの画像をダウンロードして、アプリケーションに1つずつ表示する必要があります。再フェッチを回避し、ユーザーエクスペリエンスを向上させるために、SoftReferences
とSdcardを使用してコレクションに画像を保存しています。
問題は、ビットマップのサイズについて何も知らないことです。そして結局のところ、BitmapFactory.decodeStream(InputStream)
メソッドを使用していると、OutOfMemoryExceptionsが散発的に発生します。そこで、BitmapFactory Options(sample size = 2)を使用して画像をダウンサンプリングすることにしました。これにより出力が向上しました。OOMはありませんが、これは小さい画像の品質に影響します。
そのような場合はどうすればよいですか?高解像度画像のみを選択的にダウンサンプリングする方法はありますか?
BitmapFactory.Options
クラス(私が見落としたもの)にinJustDecodeBounds
という名前のオプションがあります。
Trueに設定すると、デコーダーはnull(ビットマップなし)を返しますが、out ...フィールドは設定されたままなので、呼び出し元はピクセルにメモリを割り当てる必要なくビットマップをクエリできます。
これを使用してビットマップの実際のサイズを確認し、inSampleSize
オプションを使用してダウンサンプルすることを選択しました。これにより、ファイルのデコード中のOOMエラーが少なくとも回避されます。
参照:
1。 大きなビットマップの処理
2。 デコードする前にビットマップ情報を取得する方法
数日間、さまざまなデバイスで発生していたすべてのOutOfMemoryエラーを回避するのに苦労して、これを作成しました。
private Bitmap getDownsampledBitmap(Context ctx, Uri uri, int targetWidth, int targetHeight) {
Bitmap bitmap = null;
try {
BitmapFactory.Options outDimens = getBitmapDimensions(uri);
int sampleSize = calculateSampleSize(outDimens.outWidth, outDimens.outHeight, targetWidth, targetHeight);
bitmap = downsampleBitmap(uri, sampleSize);
} catch (Exception e) {
//handle the exception(s)
}
return bitmap;
}
private BitmapFactory.Options getBitmapDimensions(Uri uri) throws FileNotFoundException, IOException {
BitmapFactory.Options outDimens = new BitmapFactory.Options();
outDimens.inJustDecodeBounds = true; // the decoder will return null (no bitmap)
InputStream is= getContentResolver().openInputStream(uri);
// if Options requested only the size will be returned
BitmapFactory.decodeStream(is, null, outDimens);
is.close();
return outDimens;
}
private int calculateSampleSize(int width, int height, int targetWidth, int targetHeight) {
int inSampleSize = 1;
if (height > targetHeight || width > targetWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) targetHeight);
final int widthRatio = Math.round((float) width / (float) targetWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
private Bitmap downsampleBitmap(Uri uri, int sampleSize) throws FileNotFoundException, IOException {
Bitmap resizedBitmap;
BitmapFactory.Options outBitmap = new BitmapFactory.Options();
outBitmap.inJustDecodeBounds = false; // the decoder will return a bitmap
outBitmap.inSampleSize = sampleSize;
InputStream is = getContentResolver().openInputStream(uri);
resizedBitmap = BitmapFactory.decodeStream(is, null, outBitmap);
is.close();
return resizedBitmap;
}
この方法はテストしたすべてのデバイスで機能しますが、気付いていない他のプロセスを使用すると品質が向上する可能性があると思います。
私のコードが同じ状況の他の開発者を助けることを願っています。また、上級開発者が助けて、プロセスの品質低下(低下)を回避するために他のプロセスについて提案してもらえれば幸いです。
私が自分でやったことは:
inJustDecodeBounds
を使用して画像の元のサイズを取得しますinSampleSize
(イメージの品質を低下させない2の累乗)に変換する必要があります。私はこの関数を使用します:int k = Integer.highestOneBit((int)Math.floor(ratio)); if(k == 0)return 1; else return k;