[解決済み] Bitmapオブジェクトに画像を読み込む際にOutOfMemoryが発生する問題
質問
私は
ListView
各行にいくつかの画像ボタンがあります。ユーザーがリストの行をクリックすると、新しいアクティビティが起動します。カメラのレイアウトに問題があるため、独自のタブを構築する必要がありました。その結果、起動されるアクティビティは地図です。私のボタンをクリックして画像プレビューを起動すると(SDカードから画像をロード)、アプリケーションはアクティビティから戻って
ListView
アクティビティから結果ハンドラへ移動し、画像ウィジェットに過ぎない新しいアクティビティを再スタートさせます。
の画像プレビューは
ListView
はカーソルで行っており
ListAdapter
. これは非常にシンプルですが、リサイズされた画像(つまり、ピクセルではなくビットサイズを小さくしたもの)を、どのように
src
をオンザフライで画像ボタンに使用します。だから、私はちょうど携帯電話のカメラから来た画像をリサイズしました。
問題なのは
OutOfMemoryError
2つ目のアクティビティに戻り、再度起動しようとすると
- リスト・アダプタを一行ずつ簡単に構築して、その場でサイズを変更できる方法はありますか( ビット単位 )?
フォーカスの問題でタッチスクリーンで行を選択できないため、各行のウィジェット/要素のプロパティに変更を加える必要もあるため、これが望ましいと思われます。( ローラー台が使える )
- 帯域外のサイズを変更して画像を保存できることは知っていますが、私が本当にやりたいのはそれではなく、そのためのいくつかのサンプルコードがあればいいと思います。
の画像を無効化した途端
ListView
は、再び正常に動作するようになりました。
参考:こんな感じでやってました。
String[] from = new String[] { DBHelper.KEY_BUSINESSNAME, DBHelper.KEY_ADDRESS,
DBHelper.KEY_CITY, DBHelper.KEY_GPSLONG, DBHelper.KEY_GPSLAT,
DBHelper.KEY_IMAGEFILENAME + ""};
int[] to = new int[] { R.id.businessname, R.id.address, R.id.city, R.id.gpslong,
R.id.gpslat, R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
ここで
R.id.imagefilename
は
ButtonImage
.
以下は私のLogCatです。
01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed
また、画像を表示する際に新たなエラーが発生しました。
22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri:
22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed
解決方法は?
その Androidトレーニング クラス、"。 ビットマップの効率的な表示 java.lang.OutOfMemoryError: bitmap size exceeds VM budget when loading Bitmaps "という例外を理解し対処するための素晴らしい情報を提供しています。
ビットマップの寸法と種類を読む
は
BitmapFactory
クラスはいくつかのデコードメソッドを提供します (
decodeByteArray()
,
decodeFile()
,
decodeResource()
など)を作成するために
Bitmap
を様々なソースから取得することができます。画像データソースに応じて、最も適切なデコード方法を選択してください。これらのメソッドは構築されたビットマップのためにメモリを確保しようとするため、簡単に
OutOfMemory
例外が発生します。各タイプのデコードメソッドには追加のシグネチャがあり、それを使ってデコードのオプションを指定することができます。
BitmapFactory.Options
クラスがあります。を設定することで
inJustDecodeBounds
プロパティを
true
を返し、デコードはメモリの割り当てを回避します。
null
をビットマップオブジェクトに設定しますが
outWidth
,
outHeight
と
outMimeType
. この手法により、ビットマップの構築(およびメモリの割り当て)の前に、画像データの寸法とタイプを読み取ることができます。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
を回避するために
java.lang.OutOfMemory
ただし、利用可能なメモリに収まるような予測可能なサイズの画像データを提供するソースを絶対的に信頼できる場合は、デコードする前にビットマップの寸法を確認してください。
縮小版をメモリに読み込む
画像の寸法がわかったので、完全な画像をメモリに読み込むか、代わりにサブサンプル版を読み込むかを決定するために使用できます。以下は、検討すべきいくつかの要素です。
- フル画像をメモリに読み込んだ場合のメモリ使用量の見積もり。
- アプリケーションに必要な他のメモリを考慮した上で、この画像の読み込みにコミットできるメモリ量です。
- 画像を読み込む対象のImageViewまたはUIコンポーネントの寸法。
- 現在のデバイスの画面サイズと密度。
例えば、1024x768ピクセルの画像をメモリにロードしても、最終的に128x96ピクセルのサムネイルとして
ImageView
.
デコーダーに画像をサブサンプリングして、より小さいバージョンをメモリに読み込むように指示するには
inSampleSize
から
true
をあなたの
BitmapFactory.Options
オブジェクトを作成します。例えば、解像度2048x1536の画像を
inSampleSize
4の場合、約512x384のビットマップが生成されます。これをメモリにロードすると、フル画像で12MBではなく、0.75MBを使用します(ビットマップの構成が
ARGB_8888
). ここでは、対象となる幅と高さから、2のべき乗のサンプルサイズ値を算出する方法を紹介します。
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
備考 : 2のべき乗の値を計算するのは、デコーダが、その値を使用するためです。 に従って、2の最も近い累乗に切り捨てて最終的な値とします。
inSampleSize
のドキュメントを参照してください。
このメソッドを使用するには、まずデコードを
inJustDecodeBounds
に設定します。
true, pass the options through and then decode again using the new
inSampleSize
value and
inJustDecodeBounds
set to
false` です。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
この方法を用いると、任意に大きなサイズのビットマップを簡単に
ImageView
のように、100x100ピクセルのサムネイルを表示します。
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
他のソースからのビットマップをデコードする場合も、同様の手順で、適切な
BitmapFactory.decode*
メソッドを使用します。
関連
-
adb シェルがデバイスのオフラインを求めるプロンプトを表示する
-
Android.mk:7: *** セパレータがありません。
-
AndroidエミュレーターのADBサーバーがACKしない問題
-
gitlab 設定エラー。リモートリポジトリから読み込めなかったか、ホストキーの検証に失敗しました。
-
プログラム "git.exe "を実行できない場合の正しい解決方法です。CreateProcessエラー=2
-
ジャークとして。起動アクティビティを特定できませんでした。デフォルトのアクティビティが見つかりません アクティビティ起動中のエラー
-
ArrayAdapter は、リソース ID が TextView であることが必要です。
-
Android studioのインストールと問題発生、Emulator: PANIC: AVDのシステムパスが見つかりません。
-
Google PlayデバイスはPlay保護機構の認証を受けていません。
-
Androidで、onTouchEventでダブルクリックを実装し、ダブルクリックイベントとして判定する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
gitlab 設定エラー。リモートリポジトリから読み込めなかったか、ホストキーの検証に失敗しました。
-
AndroidStudio reports Could not resolve all artifacts for configuration ':app:classpath'.
-
android:EMSのプロパティ
-
JVMのエラーに遭遇しました。Java Runtime Environmentによって致命的なエラーが検出されました。
-
GoogleMapと連携し、位置情報の取得が可能
-
Android カスタムスピナーコントロールのドロップダウン・ボックスの実装
-
Android基本アプレット
-
アンドロイドシェイプ、グラデーション、角丸、ボーダーラインの設定
-
アンドロイドの遅延実行のいくつかの方法
-
Android.support.v7.widget.Toolbar が見つかりませんでした。