android bitmap out-of-memory error after getting s

2019-08-03 06:13发布

问题:

I have a program that is supposed to grab an image from a user's gallery and then display the image in a subsequent activity. As part of my testing, I try to do the operation twice in a row: in ViewImageActivity I click on the button that takes me to the gallery; pick an image; then see the image in FriendsActivity. Then I click the back button and repeat the process. The second time around I always get a ava.lang.OutOfMemoryError. I am including the error log:

04-26 09:43:57.911: W/dalvikvm(30841): threadid=1: thread exiting with uncaught exception (group=0x40c231f8)
04-26 09:43:57.918: E/AndroidRuntime(30841): FATAL EXCEPTION: main
04-26 09:43:57.918: E/AndroidRuntime(30841): java.lang.OutOfMemoryError
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:324)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at com.example.game.utils.FileUtils.imageFromGallery(FileUtils.java:87)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at com.example.game.utils.FileUtils.unmarshallBitmap(FileUtils.java:71)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at com.example.game.FriendsActivity.onCreate(FriendsActivity.java:46)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.Activity.performCreate(Activity.java:4638)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1051)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1940)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2001)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.ActivityThread.access$600(ActivityThread.java:129)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1153)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.os.Handler.dispatchMessage(Handler.java:99)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.os.Looper.loop(Looper.java:137)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at android.app.ActivityThread.main(ActivityThread.java:4516)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at java.lang.reflect.Method.invokeNative(Native Method)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at java.lang.reflect.Method.invoke(Method.java:511)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
04-26 09:43:57.918: E/AndroidRuntime(30841):    at dalvik.system.NativeStart.main(Native Method)
04-26 09:44:00.997: I/Process(30841): Sending signal. PID: 30841 SIG: 9

My program is written like so:

ViewImageActivity dispatch intent to get photo from image gallery; then onActivityResult calls FriendsActivity. FriendsActivity in turn calls FileUtils's static method unmarshallBitmap to get the image for displaying. See following snippets:

ViewImageActivity:

public void dispatchGalleryIntent(View view) {
    Intent gallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(gallery, LOAD_IMAGE_REQUEST_CODE);
}

 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == LOAD_IMAGE_REQUEST_CODE) {
            imageUri = data.getData();
        }
        dispatchIntentToFriendsActivity();
    }
}

private void dispatchIntentTo FriendsActivity() {
    Intent intent = new Intent(this, FriendsActivity.class);
    intent.putExtra(IMAGE_URI, imageUri);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);
}

FriendsActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_friends);
    Uri imageUri = (Uri) getIntent().getExtras().get(IMAGE_URI);
    myImage = FileUtils.unmarshallBitmap(imageUri, getContentResolver());

      ...
}

FileUtils

public static Bitmap unmarshallBitmap(Uri imageUri, ContentResolver resolver) {
   return imageFromGallery(imageUri, resolver);
}

private static Bitmap imageFromGallery(Uri imageUri, ContentResolver resolver) {
        try {
            String[] filePathColumn = { MediaStore.Images.Media.DATA };
            Cursor cursor = resolver.query(imageUri, filePathColumn, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String picturePath = cursor.getString(columnIndex);
            cursor.close();
            return BitmapFactory.decodeFile(picturePath);
        } catch (Exception x) {
            return null;
        }
    }

BTW: I already saw How to solve the Out of Memory issue while displaying image in android?. My image loads fine the first time. The problem is if user change their mind and decide to choose a different image (back button and repeat), then the app crash as explained above.

回答1:

Recycle the currently loaded bitmap image when the user presses the back button and goes of a different image

myImage.recycle();


回答2:

You should prepare the image for display by loading it with options.inJustDecodeBounds = true; and then adjusting the samplesize.

See: http://developer.android.com/training/displaying-bitmaps/

Apart from that, are you calling bitmap.recycle() when you no longer need the bitmap? The first could still be in memory when you load the second, causing the error.