1

カメラから写真を撮り、それらの画像をアプリのプロフィール写真として使用することになっているAndroid用のアプリケーションを開発しています。ただし、アプリは最初の 3 ~ 4 枚の写真では問題なく動作しますが、さらに写真を撮ろうとすると、アプリがクラッシュします。原因はメモリーリーク。

カメラの意図を開始するためのコードは次のとおりです。

String fileName = "temp.jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mCapturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(takePictureIntent,RESULT_LOAD_IMAGE_CAMERA);

インテントを受け取るコードは次のとおりです。

if (requestCode == RESULT_LOAD_IMAGE_CAMERA && resultCode == RESULT_OK ) {
    String[] projection = { MediaStore.Images.Media.DATA};
    Cursor cursor = managedQuery(mCapturedImageURI, projection, null, null, null);
    final int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String capturedImageFilePath = cursor.getString(column_index_data);
    profilePic.setImageURI(Uri.fromFile(new  File(capturedImageFilePath)));
}

ログは次のとおりです。

02-28 18:28:36.727: E/dalvikvm-heap(4081): 9830400-byte external allocation too large for this process.
02-28 18:28:36.727: E/GraphicsJNI(4081): VM won't let us allocate 9830400 bytes
02-28 18:28:36.824: E/AndroidRuntime(4081): FATAL EXCEPTION: main
02-28 18:28:36.824: E/AndroidRuntime(4081): java.lang.OutOfMemoryError: bitmap size    exceeds VM budget
02-28 18:28:36.824: E/AndroidRuntime(4081):     at   android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at   android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:562)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at  android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:426)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.widget.ImageView.resolveUri(ImageView.java:509)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.widget.ImageView.setImageURI(ImageView.java:293)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.octanetech.cortes.ProfileActivity.onActivityResult(ProfileActivity.java:596)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.Activity.dispatchActivityResult(Activity.java:3890)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3557)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.access$2800(ActivityThread.java:125)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2063)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.os.Looper.loop(Looper.java:123)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.main(ActivityThread.java:4627)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at java.lang.reflect.Method.invokeNative(Native Method)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at java.lang.reflect.Method.invoke(Method.java:521)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at dalvik.system.NativeStart.main(Native Method)

どんな助けでも大歓迎です。

4

3 に答える 3

3

最後に、私は自分で問題を解決しました。メモリ リークを引き起こした主な問題は、ビットマップ オブジェクトをリサイクルしていなかったことです。ビットマップ オブジェクトを別のビットマップ イメージに置き換えただけです。オブジェクトが別のビットマップ イメージに置き換えられたと思っても、メモリには以前のビットマップ イメージが存在していました。そのため、カメラから複数の画像を取得すると、ビットマップ画像が積み重なってメモリ不足の例外が発生しました。

そのため、新しい画像を Bitmap オブジェクトに割り当てる前に、Bitmap 画像をリサイクル (削除) するトリックを行いました。ちょうど使った

mImageBitmap.recycle();

これにより、以前のビットマップ イメージがフラッシュされ、メモリ リークは発生しませんでした。それが他の人にも役立つことを願っています。

于 2013-03-04T05:39:38.680 に答える
3

この行を置き換えます

profilePic.setImageURI(Uri.fromFile(new  File(capturedImageFilePath)));

SDカードから直接画像を読み込んでいますが、サイズが大きく、メモリの問題を引き起こしている可能性があります.

これを試して

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=8;      // 1/8 of original image
Bitmap b = BitmapFactory.decodeFile(capturedImageFilePath,options);
profilePic.setImageBitmap(b);
于 2013-02-28T13:25:48.177 に答える
0

次のように inSampleSize を使用して、より大きなビットマップをスケーリングしてみてください

public intSampleSize

値 > 1 に設定すると、メモリを節約するために小さいイメージを返し、元のイメージをサブサンプリングするようにデコーダに要求します。

//decodes image and scales it to reduce memory consumption
    private Bitmap decodeFile(File f){
        try {
            //decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            FileInputStream stream1=new FileInputStream(f);
            BitmapFactory.decodeStream(stream1,null,o);
            stream1.close();

            //Find the correct scale value. It should be the power of 2.
            final int REQUIRED_SIZE=70;
            int width_tmp=o.outWidth, height_tmp=o.outHeight;
            int scale=1;
            while(true){
                if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                    break;
                width_tmp/=2;
                height_tmp/=2;
                scale*=2;
            }

            //decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize=scale;
            FileInputStream stream2=new FileInputStream(f);
            Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
            stream2.close();
            return bitmap;
        } catch (FileNotFoundException e) {
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

これがあなたに役立つことを願っています:

于 2013-02-28T15:16:30.470 に答える