在Android中的Uri内存异常和位图

时间:2013-07-23 09:50:47

标签: android bitmap

我有应用程序,我从相机获取照片并在imageview中显示它。

Uri bitmapPictureUri = intent.getParcelableExtra(TaskActivity.PHOTO);
            Bitmap bitmap = null;

            try {

                bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), bitmapPictureUri);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            int nh = (int) (bitmap.getHeight() * (512.0 / bitmap.getWidth()));
            bitmapPicture = Bitmap.createScaledBitmap(bitmap, 512, nh, true);
            WeakReference<Bitmap> bm = new WeakReference<Bitmap>(bitmap);
            WeakReference<Bitmap> bm2 = new WeakReference<Bitmap>(bitmapPicture);
            picture.setImageBitmap(bm2.get());

一切正常,直到我改变方向。当我第一次改变时没关系,但是当我再次旋转时,我得到了永远的记忆:

07-23 11:43:18.840: E/AndroidRuntime(12024): FATAL EXCEPTION: main
07-23 11:43:18.840: E/AndroidRuntime(12024): java.lang.OutOfMemoryError
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:529)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:601)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:803)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at PhotoController.onCreate(PhotoController.java:117)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.Activity.performCreate(Activity.java:5104)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3692)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.ActivityThread.access$700(ActivityThread.java:141)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1240)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.os.Handler.dispatchMessage(Handler.java:99)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.os.Looper.loop(Looper.java:137)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at android.app.ActivityThread.main(ActivityThread.java:5039)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at java.lang.reflect.Method.invokeNative(Native Method)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at java.lang.reflect.Method.invoke(Method.java:511)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
07-23 11:43:18.840: E/AndroidRuntime(12024):    at dalvik.system.NativeStart.main(Native Method)

任何想法如何才能避免这个问题?我尝试使用simpleSize,weakreferences,bitmap.recycle。 System.gc(),没什么。

3 个答案:

答案 0 :(得分:1)

我通过以下方式解决了我的问题:

protected void onDestroy() {
        super.onDestroy();
        bitmapPicture.recycle();
        bitmap.recycle();
        unbindDrawables(findViewById(R.id.picture_measure_picture));
        System.gc();
    }

    private void unbindDrawables(View view) {
        if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
        ((ViewGroup) view).removeAllViews();
        }
    }

答案 1 :(得分:0)

我在这里是怎么做的。您必须使用我在下面添加的decodeUri方法从URI获取位图。

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

    if (resultCode == RESULT_OK) {
            if(data != null){
                Uri dataUri = data.getData();

                Bitmap bitmap;
                try {
                    bitmap = decodeUri(dataUri);
                    imageView.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }

                }

    }
}

此方法将优化内存,您的异常将永远不会再次发生。

   private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 140;

    // Find the correct scale value. It should be the power of 2.
    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;
    return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);

}

P.S: - 我在SO上读到的这个decodeUri方法,不是我的代码。干杯!!

答案 2 :(得分:0)

使用imageloader类。这将解决位图内存异常问题。

http://www.androidhive.info/2012/07/android-loading-image-from-url-http/